├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.yml │ └── bug_report.yml ├── workflows │ ├── codeql-analysis.yml │ └── ci.yml └── PULL_REQUEST_TEMPLATE.md ├── .images └── tree_example.png ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── .idea ├── copyright │ ├── profiles_settings.xml │ └── aerogel.xml ├── codeStyles │ └── codeStyleConfig.xml └── inspectionProfiles │ ├── profiles_settings.xml │ └── aerogel.xml ├── auto ├── src │ ├── processing │ │ ├── resources │ │ │ └── META-INF │ │ │ │ ├── gradle │ │ │ │ └── incremental.annotation.processors │ │ │ │ └── services │ │ │ │ ├── javax.annotation.processing.Processor │ │ │ │ └── dev.derklaro.aerogel.auto.processing.AutoEntryProcessorFactory │ │ └── java │ │ │ └── dev │ │ │ └── derklaro │ │ │ └── aerogel │ │ │ └── auto │ │ │ └── processing │ │ │ ├── internal │ │ │ ├── factory │ │ │ │ └── FactoryAutoEntryProcessorFactory.java │ │ │ ├── provides │ │ │ │ └── ProvidesAutoEntryProcessorFactory.java │ │ │ └── util │ │ │ │ └── AutoTypeEncodingUtil.java │ │ │ ├── AutoEntryProcessorFactory.java │ │ │ └── AutoEntryProcessor.java │ ├── main │ │ ├── java │ │ │ ├── module-info.java │ │ │ └── dev │ │ │ │ └── derklaro │ │ │ │ └── aerogel │ │ │ │ └── auto │ │ │ │ ├── annotation │ │ │ │ ├── Factory.java │ │ │ │ └── Provides.java │ │ │ │ ├── internal │ │ │ │ ├── provides │ │ │ │ │ └── ProvidesAutoEntryDecoder.java │ │ │ │ ├── CombinedLazyBindingCollection.java │ │ │ │ ├── factory │ │ │ │ │ ├── FactoryLazyBindingCollection.java │ │ │ │ │ └── FactoryAutoEntryDecoder.java │ │ │ │ └── util │ │ │ │ │ └── AutoDecodingUtil.java │ │ │ │ ├── AutoEntryDecoder.java │ │ │ │ └── LazyBindingCollection.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ └── dev.derklaro.aerogel.auto.AutoEntryDecoder │ └── test │ │ └── java │ │ └── dev │ │ └── derklaro │ │ └── aerogel │ │ └── auto │ │ ├── util │ │ ├── CompilationUtil.java │ │ └── TestJavaClassBuilder.java │ │ └── AerogelAutoModuleTest.java └── build.gradle.kts ├── .editorconfig ├── scoped-value-context-scope ├── src │ └── main │ │ ├── java │ │ ├── module-info.java │ │ └── dev │ │ │ └── derklaro │ │ │ └── aerogel │ │ │ └── scopedvalue │ │ │ └── ScopedValueInjectionContextScope.java │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── dev.derklaro.aerogel.internal.context.scope.InjectionContextProvider └── build.gradle.kts ├── .gitignore ├── src ├── main │ └── java │ │ ├── module-info.java │ │ └── dev │ │ └── derklaro │ │ └── aerogel │ │ ├── internal │ │ ├── member │ │ │ ├── MemberInjectionExecutor.java │ │ │ ├── MemberInjectionTracker.java │ │ │ └── DefaultMemberInjector.java │ │ ├── provider │ │ │ ├── ProviderFactory.java │ │ │ ├── DelegatingProviderFactory.java │ │ │ ├── DelegatingContextualProviderFactory.java │ │ │ ├── CascadingProviderFactory.java │ │ │ ├── InstanceProviderFactory.java │ │ │ └── ConstructingDelegatingProviderFactory.java │ │ ├── scope │ │ │ └── UnscopedScopeApplier.java │ │ ├── ConstructionException.java │ │ ├── binding │ │ │ ├── BindingOptionsImpl.java │ │ │ ├── DynamicBindingImpl.java │ │ │ ├── annotation │ │ │ │ └── BuilderAnnotationProxy.java │ │ │ └── InstalledBindingImpl.java │ │ ├── context │ │ │ ├── SelfTypeProxiedException.java │ │ │ ├── scope │ │ │ │ ├── InjectionContextScope.java │ │ │ │ └── threadlocal │ │ │ │ │ └── ThreadLocalInjectionContextScope.java │ │ │ └── UnbreakableCyclicDependencyException.java │ │ ├── injector │ │ │ ├── InjectorBuilderImpl.java │ │ │ ├── InjectorOptions.java │ │ │ └── TargetedInjectorBuilderImpl.java │ │ ├── util │ │ │ ├── PrimitiveUtil.java │ │ │ ├── NullMask.java │ │ │ ├── BindingUtil.java │ │ │ ├── UnreflectionUtil.java │ │ │ └── MapUtil.java │ │ ├── PassThroughException.java │ │ └── annotation │ │ │ └── AnnotationUtil.java │ │ ├── ProvidedBy.java │ │ ├── binding │ │ ├── ProviderWithContext.java │ │ ├── BindingOptions.java │ │ ├── builder │ │ │ └── AdvancedBindingBuilder.java │ │ └── DynamicBinding.java │ │ ├── Order.java │ │ ├── TargetedInjectorBuilder.java │ │ ├── ScopeApplier.java │ │ ├── MemberInjector.java │ │ └── InjectorBuilder.java └── test │ └── java │ └── dev │ └── derklaro │ └── aerogel │ ├── UnbreakableCircularDependencyTest.java │ ├── NullMaskTest.java │ ├── SingletonCircularTest.java │ ├── AnnotationUtilTest.java │ ├── PrimitiveUtilTest.java │ ├── CircularMemberInjectionTest.java │ └── SecondCircularDependencyTest.java ├── renovate.json ├── license.txt ├── .gitattributes ├── license_header.txt ├── gradle.properties ├── settings.gradle.kts ├── CONTRIBUTING.md └── gradlew.bat /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @derklaro 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.images/tree_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derklaro/aerogel/HEAD/.images/tree_example.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derklaro/aerogel/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /auto/src/processing/resources/META-INF/gradle/incremental.annotation.processors: -------------------------------------------------------------------------------- 1 | dev.derklaro.aerogel.auto.processing.internal.AutoEntryAnnotationProcessor,aggregating 2 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://editorconfig.org/ 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 2 11 | indent_style = space 12 | max_line_length = 120 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /scoped-value-context-scope/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module aerogel.scopedvalues { 2 | requires aerogel; 3 | requires jakarta.inject; 4 | requires static org.apiguardian.api; 5 | requires static org.jetbrains.annotations; 6 | 7 | provides dev.derklaro.aerogel.internal.context.scope.InjectionContextProvider 8 | with dev.derklaro.aerogel.scopedvalue.ScopedValueInjectionContextProvider; 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # include specific folders in .idea/ 2 | !.idea 3 | .idea/* 4 | !/.idea/copyright 5 | !/.idea/codeStyles 6 | !/.idea/inspectionProfiles 7 | 8 | # gradle 9 | .gradle/ 10 | build/ 11 | 12 | # eclipse 13 | *.classpath 14 | *.project 15 | *.settings 16 | /bin/ 17 | /subprojects/*/bin/ 18 | .metadata/ 19 | atlassian-ide-plugin.xml 20 | 21 | # NetBeans 22 | .nb-gradle 23 | .nb-gradle-properties 24 | 25 | # Vim 26 | *.sw[nop] 27 | 28 | # Emacs 29 | *~ 30 | \#*\# 31 | .\#* 32 | 33 | # Textmate 34 | .textmate 35 | 36 | # Sublime Text 37 | *.sublime-* 38 | 39 | # jEnv 40 | .java-version 41 | 42 | # macOS 43 | .DS_Store 44 | 45 | # HPROF 46 | *.hprof 47 | 48 | # Work dirs 49 | /incoming-distributions 50 | /intTestHomeDir 51 | 52 | # Logs 53 | /*.log 54 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module aerogel { 2 | requires jakarta.inject; 3 | requires io.leangen.geantyref; 4 | requires static org.apiguardian.api; 5 | requires static org.jetbrains.annotations; 6 | 7 | exports dev.derklaro.aerogel; 8 | exports dev.derklaro.aerogel.registry; 9 | exports dev.derklaro.aerogel.binding; 10 | exports dev.derklaro.aerogel.binding.key; 11 | exports dev.derklaro.aerogel.binding.builder; 12 | 13 | exports dev.derklaro.aerogel.internal.context; 14 | exports dev.derklaro.aerogel.internal.context.scope; 15 | 16 | uses dev.derklaro.aerogel.internal.context.scope.InjectionContextProvider; 17 | provides dev.derklaro.aerogel.internal.context.scope.InjectionContextProvider 18 | with dev.derklaro.aerogel.internal.context.scope.threadlocal.ThreadLocalInjectionContextProvider; 19 | } 20 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ], 6 | "labels": [ 7 | "t: dependencies" 8 | ], 9 | "reviewers": [ 10 | "derklaro" 11 | ], 12 | "packageRules": [ 13 | { 14 | "matchManagers": [ 15 | "github-actions" 16 | ], 17 | "groupName": "github actions" 18 | }, 19 | { 20 | "matchUpdateTypes": [ 21 | "patch" 22 | ], 23 | "matchPackageNames": [ 24 | "*", 25 | "!gradle" 26 | ], 27 | "groupName": "all dependencies with patch changes" 28 | } 29 | ], 30 | "prHourlyLimit": 10, 31 | "rebaseWhen": "conflicted", 32 | "rebaseLabel": "s: rebase", 33 | "stopUpdatingLabel": "s: stop updates", 34 | "commitMessagePrefix": "chore: ", 35 | "commitMessageAction": "update" 36 | } 37 | -------------------------------------------------------------------------------- /auto/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module aerogel.auto { 2 | requires aerogel; 3 | requires static org.apiguardian.api; 4 | requires static transitive java.compiler; 5 | requires static org.jetbrains.annotations; 6 | 7 | exports dev.derklaro.aerogel.auto; 8 | exports dev.derklaro.aerogel.auto.annotation; 9 | exports dev.derklaro.aerogel.auto.processing; 10 | 11 | uses dev.derklaro.aerogel.auto.AutoEntryDecoder; 12 | provides dev.derklaro.aerogel.auto.AutoEntryDecoder with 13 | dev.derklaro.aerogel.auto.internal.factory.FactoryAutoEntryDecoder, 14 | dev.derklaro.aerogel.auto.internal.provides.ProvidesAutoEntryDecoder; 15 | 16 | uses dev.derklaro.aerogel.auto.processing.AutoEntryProcessorFactory; 17 | provides dev.derklaro.aerogel.auto.processing.AutoEntryProcessorFactory with 18 | dev.derklaro.aerogel.auto.processing.internal.factory.FactoryAutoEntryProcessorFactory, 19 | dev.derklaro.aerogel.auto.processing.internal.provides.ProvidesAutoEntryProcessorFactory; 20 | 21 | provides javax.annotation.processing.Processor 22 | with dev.derklaro.aerogel.auto.processing.internal.AutoEntryAnnotationProcessor; 23 | } 24 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2025 Pasqual Koschmieder and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '00 2 * * *' 8 | 9 | concurrency: 10 | cancel-in-progress: true 11 | group: cq-${{ github.event.pull_request.number || github.job }} 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ubuntu-latest 17 | if: ${{ !startsWith(github.ref, 'refs/heads/renovate/') }} 18 | 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v5 22 | 23 | - name: Setup java 24 | uses: actions/setup-java@v5 25 | with: 26 | java-version: 25 27 | check-latest: true 28 | distribution: 'zulu' 29 | 30 | - name: Setup Gradle 31 | uses: gradle/actions/setup-gradle@v5 32 | with: 33 | cache-read-only: true 34 | add-job-summary: always 35 | 36 | - name: Initialize CodeQL 37 | uses: github/codeql-action/init@v3 38 | with: 39 | tools: linked 40 | languages: 'java' 41 | 42 | - name: Autobuild 43 | uses: github/codeql-action/autobuild@v3 44 | 45 | - name: Perform CodeQL Analysis 46 | uses: github/codeql-action/analyze@v3 47 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize as LF in the repository, OS native locally 2 | * text eol=lf 3 | 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | # These files are text and should be normalized (Convert crlf => lf) 8 | *.bash text eol=lf 9 | *.css text diff=css 10 | *.htm text diff=html 11 | *.html text diff=html 12 | *.java text diff=java 13 | *.sh text eol=lf 14 | gradlew text eol=lf 15 | 16 | # These files are binary and should be left untouched 17 | # (binary is a macro for -text -diff) 18 | *.a binary 19 | *.lib binary 20 | *.icns binary 21 | *.png binary 22 | *.jpg binary 23 | *.jpeg binary 24 | *.gif binary 25 | *.ico binary 26 | *.mov binary 27 | *.mp4 binary 28 | *.mp3 binary 29 | *.flv binary 30 | *.fla binary 31 | *.swf binary 32 | *.gz binary 33 | *.zip binary 34 | *.jar binary 35 | *.tar binary 36 | *.tar.gz binary 37 | *.7z binary 38 | *.ttf binary 39 | *.pyc binary 40 | *.gpg binary 41 | *.bin binary 42 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | 7 | 8 | ### Type of change 9 | 10 | 13 | 14 | - [X] Bug fix (non-breaking change which fixes an issue) 15 | - [X] New feature (non-breaking change which adds functionality) 16 | - [X] Breaking change (fix or feature that would cause existing functionality to not work as expected) 17 | - [X] This change requires a documentation update 18 | 19 | ### Checklist: 20 | 21 | 24 | 25 | - [ ] My code follows the style guidelines 26 | - [ ] I have added documentation to all new methods and updated the existing ones if necessary 27 | - [ ] The changes do not lead to compilation warnings which are resolvable 28 | - [ ] I added test for the new code I've added to the project 29 | - [ ] New and existing unit tests pass with the proposed changes 30 | - [ ] This pull request has no conflicts with the base branch (preferably a linear history) 31 | -------------------------------------------------------------------------------- /license_header.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | concurrency: 8 | cancel-in-progress: true 9 | group: build-${{ github.event.pull_request.number || github.ref }} 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | java: [ '17', '21', '25' ] 17 | name: ${{ matrix.java }} 18 | 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v5 22 | 23 | - name: Setup java 24 | uses: actions/setup-java@v5 25 | with: 26 | check-latest: true 27 | distribution: 'zulu' 28 | java-version: ${{ matrix.java }} 29 | 30 | - name: Setup Gradle 31 | uses: gradle/actions/setup-gradle@v5 32 | with: 33 | add-job-summary: always 34 | cache-cleanup: on-success 35 | cache-read-only: ${{ github.ref != 'refs/heads/v3' }} 36 | 37 | - name: Run build and tests 38 | run: ./gradlew clean build test --no-daemon 39 | 40 | - name: Publish test summary 41 | if: ${{ always() }} 42 | uses: EnricoMi/publish-unit-test-result-action@v2 43 | with: 44 | files: "**/build/test-results/test/TEST-*.xml" 45 | comment_mode: ${{ github.event_name == 'pull_request' && 'always' || 'off' }} 46 | -------------------------------------------------------------------------------- /auto/src/processing/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of aerogel, licensed under the MIT License (MIT). 3 | # 4 | # Copyright (c) 2021-2025 Pasqual K. and contributors 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | dev.derklaro.aerogel.auto.processing.internal.AutoEntryAnnotationProcessor 26 | -------------------------------------------------------------------------------- /.idea/copyright/aerogel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /scoped-value-context-scope/src/main/resources/META-INF/services/dev.derklaro.aerogel.internal.context.scope.InjectionContextProvider: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of aerogel, licensed under the MIT License (MIT). 3 | # 4 | # Copyright (c) 2021-2025 Pasqual K. and contributors 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | dev.derklaro.aerogel.scopedvalue.ScopedValueInjectionContextProvider 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F4A1 Feature request" 2 | description: "Create an issue describing a feature that would be nice to have" 3 | title: '[Request]: ' 4 | labels: [ "enhancement" ] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: "Thanks for taking the time file an issue request." 10 | 11 | - type: dropdown 12 | id: area 13 | attributes: 14 | label: Area 15 | description: "In which area of aerogel do you want to see the new feature?" 16 | options: 17 | - Core 18 | - Auto 19 | - Kotlin-Extensions 20 | - New module 21 | validations: 22 | required: true 23 | 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: Describe the new feature 28 | description: "Describe the new feature you want to see in aerogel with enough detail for everyone to understand" 29 | validations: 30 | required: true 31 | 32 | - type: textarea 33 | id: current-workaround 34 | attributes: 35 | label: Is there a workaround you are currently using? 36 | description: "Describe the workaround in a few sentences you are currently using if there is one" 37 | 38 | - type: checkboxes 39 | id: terms 40 | attributes: 41 | label: Terms 42 | description: "Please check if there are no other issues that already target the described feature" 43 | options: 44 | - label: "Yes i did" 45 | required: true 46 | -------------------------------------------------------------------------------- /auto/src/main/resources/META-INF/services/dev.derklaro.aerogel.auto.AutoEntryDecoder: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of aerogel, licensed under the MIT License (MIT). 3 | # 4 | # Copyright (c) 2021-2025 Pasqual K. and contributors 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | dev.derklaro.aerogel.auto.internal.factory.FactoryAutoEntryDecoder 26 | dev.derklaro.aerogel.auto.internal.provides.ProvidesAutoEntryDecoder 27 | -------------------------------------------------------------------------------- /auto/src/processing/resources/META-INF/services/dev.derklaro.aerogel.auto.processing.AutoEntryProcessorFactory: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of aerogel, licensed under the MIT License (MIT). 3 | # 4 | # Copyright (c) 2021-2025 Pasqual K. and contributors 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | dev.derklaro.aerogel.auto.processing.internal.factory.FactoryAutoEntryProcessorFactory 26 | dev.derklaro.aerogel.auto.processing.internal.provides.ProvidesAutoEntryProcessorFactory 27 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of aerogel, licensed under the MIT License (MIT). 3 | # 4 | # Copyright (c) 2021-2025 Pasqual K. and contributors 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | org.gradle.caching=true 26 | org.gradle.parallel=true 27 | org.gradle.warning.mode=all 28 | org.gradle.logging.stacktrace=all 29 | org.gradle.configureondemand=true 30 | org.gradle.configuration-cache=true 31 | org.gradle.configuration-cache.problems=fail 32 | org.gradle.jvmargs=-Xmx512m -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 33 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/member/MemberInjectionExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.member; 26 | 27 | import org.jetbrains.annotations.Nullable; 28 | 29 | @FunctionalInterface 30 | public interface MemberInjectionExecutor { 31 | 32 | void executeInjection(@Nullable Object constructedInstance) throws Throwable; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/provider/ProviderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.provider; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import org.apiguardian.api.API; 29 | import org.jetbrains.annotations.NotNull; 30 | 31 | @FunctionalInterface 32 | @API(status = API.Status.INTERNAL, since = "3.0") 33 | public interface ProviderFactory { 34 | 35 | @NotNull 36 | ProviderWithContext constructProvider(); 37 | } 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F41E Bug report" 2 | description: "Create an issue which describes a bug in aerogel" 3 | title: '[Bug]: ' 4 | labels: [ "bug" ] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: "Thanks for taking the time to file this bug report!" 10 | 11 | - type: dropdown 12 | id: area 13 | attributes: 14 | label: Area 15 | description: "In which area of aerogel did you encounter the bug?" 16 | options: 17 | - Core 18 | - Auto 19 | - Kotlin-Extensions 20 | validations: 21 | required: true 22 | 23 | - type: textarea 24 | id: what-happened 25 | attributes: 26 | label: "What happened?" 27 | description: "Please describe in a few sentences what happened" 28 | value: "A bug happened :/" 29 | validations: 30 | required: true 31 | 32 | - type: textarea 33 | id: what-should-happen 34 | attributes: 35 | label: "What should happen?" 36 | description: "Please describe in a few sentences what you expected to happen" 37 | value: "No bug i suppose :)" 38 | validations: 39 | required: true 40 | 41 | - type: textarea 42 | id: code 43 | attributes: 44 | label: "The issue triggering code" 45 | description: "Please append (if possible) the code that triggered the described issue" 46 | 47 | - type: textarea 48 | id: exception 49 | attributes: 50 | label: "The triggered exception" 51 | description: "Please append (if possible) the exception which happened. There might be no exception." 52 | 53 | - type: checkboxes 54 | id: terms 55 | attributes: 56 | label: Terms 57 | description: | 58 | Please check if there are no other issues that already target the described issue and if you filled everything 59 | to the best of our knowledge and belief 60 | options: 61 | - label: "Yes i did" 62 | required: true 63 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 26 | 27 | pluginManagement { 28 | includeBuild("build-logic") 29 | repositories { 30 | gradlePluginPortal() 31 | } 32 | } 33 | 34 | plugins { 35 | id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" 36 | } 37 | 38 | dependencyResolutionManagement { 39 | repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS 40 | repositories { 41 | mavenCentral() 42 | } 43 | } 44 | 45 | rootProject.name = "aerogel" 46 | include("scoped-value-context-scope") 47 | include("auto") 48 | 49 | // prefixes each subproject with 'aerogel-' 50 | rootProject.children.forEach { 51 | it.name = "aerogel-${it.name}" 52 | } 53 | -------------------------------------------------------------------------------- /auto/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | description = "Extension for aerogel supporting automatic binding creation compile and runtime based" 26 | 27 | dependencies { 28 | api(projects.aerogel) 29 | testImplementation(libs.lombok) 30 | testImplementation(libs.javapoet) 31 | testImplementation(libs.compileTesting) { 32 | exclude("com.google.auto.value", "auto-value") 33 | } 34 | } 35 | 36 | java { 37 | sourceSets["main"].java { 38 | srcDir("src/processing/java") 39 | } 40 | sourceSets["main"].resources { 41 | srcDir("src/processing/resources") 42 | } 43 | } 44 | 45 | tasks.withType { 46 | jvmArgs("--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED") 47 | } 48 | 49 | configurePublishing("java") 50 | -------------------------------------------------------------------------------- /scoped-value-context-scope/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | description = "Extension for aerogel that uses scoped values for injection context scopes" 26 | 27 | dependencies { 28 | api(projects.aerogel) 29 | } 30 | 31 | tasks.withType { 32 | sourceCompatibility = JavaVersion.VERSION_25.toString() 33 | targetCompatibility = JavaVersion.VERSION_25.toString() 34 | } 35 | 36 | tasks.withType { 37 | val options = options as? StandardJavadocDocletOptions ?: return@withType 38 | options.addStringOption("-release", "25") 39 | } 40 | 41 | extensions.configure { 42 | toolchain { 43 | vendor = JvmVendorSpec.AZUL 44 | languageVersion = JavaLanguageVersion.of(25) 45 | } 46 | } 47 | 48 | configurePublishing("java") 49 | -------------------------------------------------------------------------------- /auto/src/test/java/dev/derklaro/aerogel/auto/util/CompilationUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.util; 26 | 27 | import com.google.testing.compile.Compiler; 28 | import dev.derklaro.aerogel.auto.processing.internal.AutoEntryAnnotationProcessor; 29 | import java.io.File; 30 | import java.util.List; 31 | 32 | public final class CompilationUtil { 33 | 34 | private CompilationUtil() { 35 | throw new UnsupportedOperationException(); 36 | } 37 | 38 | public static Compiler javacCompilerWithAerogelProcessor() { 39 | return Compiler.javac() 40 | .withProcessors(new AutoEntryAnnotationProcessor()) 41 | // relative to the auto module root path 42 | .withClasspath(List.of(new File("build/classes/java/main"))); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/scope/UnscopedScopeApplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.scope; 26 | 27 | import dev.derklaro.aerogel.ScopeApplier; 28 | import dev.derklaro.aerogel.binding.ProviderWithContext; 29 | import dev.derklaro.aerogel.binding.key.BindingKey; 30 | import java.util.List; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | public final class UnscopedScopeApplier implements ScopeApplier { 34 | 35 | public static final ScopeApplier INSTANCE = new UnscopedScopeApplier(); 36 | 37 | private UnscopedScopeApplier() { 38 | } 39 | 40 | @Override 41 | public @NotNull ProviderWithContext applyScope( 42 | @NotNull List> keys, 43 | @NotNull ProviderWithContext original 44 | ) { 45 | return original; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/ConstructionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal; 26 | 27 | import org.jetbrains.annotations.NotNull; 28 | import org.jetbrains.annotations.Nullable; 29 | 30 | public final class ConstructionException extends IllegalStateException { 31 | 32 | private ConstructionException(@NotNull String message, @Nullable Throwable cause) { 33 | super(message, cause); 34 | } 35 | 36 | public static @NotNull ConstructionException of(@NotNull Object errorSource) { 37 | return of(errorSource, null); 38 | } 39 | 40 | public static @NotNull ConstructionException of(@NotNull Object errorSource, @Nullable Throwable cause) { 41 | String msg = "Unable to construct instance value using " + errorSource; 42 | return new ConstructionException(msg, cause); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to contribute 2 | ======== 3 | 4 | We all love open source and work others put into projects. We'd love to accept patches from you. There are some small 5 | things you should do before contributing to this project. 6 | 7 | ### A new feature 8 | 9 | If you want to add a new feature to the project it might be a good idea to open an issue and describe the feature before 10 | writing the code and getting rejected because the feature is not needed. If you are convinced that the feature is so 11 | good of an idea that no discussion is necessary to add it - feel free to do so. 12 | 13 | ### Submitting a pull request 14 | 15 | There is a checklist of things you should do before submitting a pull request. This checklist will be there when you 16 | create it. Ensure that you can tick everything on that list - except for the situation of creating a draft pull request. 17 | In this case ensure you can tick everything before clicking on "Ready for review". Here are all points you should 18 | consider done: 19 | 20 | - The issue I fixed/closed with the pr is linked to it (if there is an issue) 21 | - My code follows the style guidelines 22 | - I have added documentation to all new methods and updated the existing ones if necessary 23 | - The changes do not lead to compilation warnings which are resolvable 24 | - I added test for the new code I've added to the project 25 | - New and existing unit tests pass with the proposed changes 26 | - This pull request has no conflicts with the base branch (preferably a linear history) 27 | 28 | ### Further reading 29 | 30 | - [How to fork a repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) 31 | - [How to create a pull request](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) 32 | - [How to write good commit messages](https://www.freecodecamp.org/news/writing-good-commit-messages-a-practical-guide/) 33 | - [Google java style guide](https://google.github.io/styleguide/javaguide.html) 34 | - [GitHub Blog - the perfect pull request](https://github.blog/2015-01-21-how-to-write-the-perfect-pull-request/) 35 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/member/MemberInjectionTracker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.member; 26 | 27 | import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; 28 | 29 | final class MemberInjectionTracker { 30 | 31 | private static final AtomicReferenceFieldUpdater INJECTED_UPDATER 32 | = AtomicReferenceFieldUpdater.newUpdater(MemberInjectionTracker.class, Boolean.class, "injected"); 33 | 34 | private volatile Boolean injected = Boolean.FALSE; 35 | 36 | public boolean markInjected() { 37 | if (this.injected == Boolean.TRUE) { 38 | // field was already injected 39 | return false; 40 | } else { 41 | // returns true if the current field value is FALSE 42 | return INJECTED_UPDATER.compareAndSet(this, Boolean.FALSE, Boolean.TRUE); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/UnbreakableCircularDependencyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import jakarta.inject.Inject; 28 | import org.junit.jupiter.api.Assertions; 29 | import org.junit.jupiter.api.Test; 30 | 31 | public class UnbreakableCircularDependencyTest { 32 | 33 | @Test 34 | void unbreakableCycleShouldThrowException() { 35 | Injector injector = Injector.newInjector(); 36 | Exception thrown = Assertions.assertThrows(RuntimeException.class, () -> injector.instance(A.class)); 37 | Assertions.assertTrue(thrown.getMessage().startsWith("Detected cyclic dependency while constructing")); 38 | } 39 | 40 | private static final class A { 41 | 42 | @Inject 43 | public A(B b) { 44 | 45 | } 46 | } 47 | 48 | private static final class B { 49 | 50 | @Inject 51 | public B(A a) { 52 | 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /auto/src/test/java/dev/derklaro/aerogel/auto/AerogelAutoModuleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto; 26 | 27 | import dev.derklaro.aerogel.auto.annotation.Factory; 28 | import dev.derklaro.aerogel.auto.annotation.Provides; 29 | import dev.derklaro.aerogel.registry.Registry; 30 | import org.junit.jupiter.api.Assertions; 31 | import org.junit.jupiter.api.Test; 32 | 33 | public class AerogelAutoModuleTest { 34 | 35 | @Test 36 | void testDecodersAreDetectedViaSPI() { 37 | AerogelAutoModule module = AerogelAutoModule.newInstance(); 38 | Registry.WithKeyMapping decoderRegistry = module.decoderRegistry(); 39 | Assertions.assertEquals(2, decoderRegistry.entryCount()); 40 | Assertions.assertTrue(decoderRegistry.get(Factory.CODEC_ID).isPresent()); 41 | Assertions.assertTrue(decoderRegistry.get(Provides.CODEC_ID).isPresent()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /auto/src/processing/java/dev/derklaro/aerogel/auto/processing/internal/factory/FactoryAutoEntryProcessorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.processing.internal.factory; 26 | 27 | import dev.derklaro.aerogel.auto.processing.AutoEntryProcessor; 28 | import dev.derklaro.aerogel.auto.processing.AutoEntryProcessorFactory; 29 | import dev.derklaro.aerogel.auto.processing.internal.util.AutoTypeEncoder; 30 | import javax.annotation.processing.ProcessingEnvironment; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | public final class FactoryAutoEntryProcessorFactory implements AutoEntryProcessorFactory { 34 | 35 | @Override 36 | public @NotNull AutoEntryProcessor constructProcessor(@NotNull ProcessingEnvironment environment) { 37 | AutoTypeEncoder typeEncoder = AutoTypeEncoder.forProcessingEnvironment(environment); 38 | return new FactoryAutoEntryProcessor(typeEncoder); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | 3 | # plugins 4 | spotless = "8.0.0" 5 | nexusPublish = "2.0.0" 6 | checkstyleTools = "11.1.0" 7 | 8 | # dependencies 9 | geantyref = "2.0.1" 10 | apiGuardian = "1.1.2" 11 | annotations = "26.0.2-1" 12 | jakartaInject = "2.0.1" 13 | 14 | # testing 15 | junit = "6.0.0" 16 | lombok = "1.18.42" 17 | javapoet = "1.13.0" 18 | compileTesting = "0.23.0" 19 | 20 | 21 | [libraries] 22 | 23 | # dependencies 24 | annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" } 25 | geantyref = { group = "io.leangen.geantyref", name = "geantyref", version.ref = "geantyref" } 26 | apiGuardian = { group = "org.apiguardian", name = "apiguardian-api", version.ref = "apiGuardian" } 27 | jakartaInjectApi = { group = "jakarta.inject", name = "jakarta.inject-api", version.ref = "jakartaInject" } 28 | 29 | # junit 30 | junitApi = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } 31 | junitEngine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" } 32 | junitLauncher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit" } 33 | junitVintageEngine = { group = "org.junit.vintage", name = "junit-vintage-engine", version.ref = "junit" } 34 | 35 | # testing 36 | lombok = { group = "org.projectlombok", name = "lombok", version.ref = "lombok" } 37 | javapoet = { group = "com.squareup", name = "javapoet", version.ref = "javapoet" } 38 | jakartaInjectTck = { group = "jakarta.inject", name = "jakarta.inject-tck", version.ref = "jakartaInject" } 39 | compileTesting = { group = "com.google.testing.compile", name = "compile-testing", version.ref = "compileTesting" } 40 | 41 | # dummy versions, just here for renovate to detect that there is something to update 42 | checkstyleTools = { group = "com.puppycrawl.tools", name = "checkstyle", version.ref = "checkstyleTools" } 43 | 44 | 45 | [bundles] 46 | 47 | junit = ["junitApi", "junitEngine", "junitVintageEngine"] 48 | 49 | 50 | [plugins] 51 | 52 | spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } 53 | nexusPublish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexusPublish" } 54 | -------------------------------------------------------------------------------- /auto/src/processing/java/dev/derklaro/aerogel/auto/processing/internal/provides/ProvidesAutoEntryProcessorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.processing.internal.provides; 26 | 27 | import dev.derklaro.aerogel.auto.processing.AutoEntryProcessor; 28 | import dev.derklaro.aerogel.auto.processing.AutoEntryProcessorFactory; 29 | import dev.derklaro.aerogel.auto.processing.internal.util.AutoTypeEncoder; 30 | import javax.annotation.processing.ProcessingEnvironment; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | public final class ProvidesAutoEntryProcessorFactory implements AutoEntryProcessorFactory { 34 | 35 | @Override 36 | public @NotNull AutoEntryProcessor constructProcessor(@NotNull ProcessingEnvironment environment) { 37 | AutoTypeEncoder typeEncoder = AutoTypeEncoder.forProcessingEnvironment(environment); 38 | return new ProvidesAutoEntryProcessor(typeEncoder); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/binding/BindingOptionsImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.binding; 26 | 27 | import dev.derklaro.aerogel.binding.BindingOptions; 28 | import java.lang.invoke.MethodHandles; 29 | import java.util.Optional; 30 | import org.jetbrains.annotations.NotNull; 31 | import org.jetbrains.annotations.Nullable; 32 | 33 | public final class BindingOptionsImpl implements BindingOptions { 34 | 35 | private final MethodHandles.Lookup memberLookup; 36 | 37 | public BindingOptionsImpl(@Nullable MethodHandles.Lookup memberLookup) { 38 | this.memberLookup = memberLookup; 39 | } 40 | 41 | @Override 42 | public @NotNull Optional memberLookup() { 43 | return Optional.ofNullable(this.memberLookup); 44 | } 45 | 46 | public @NotNull BindingOptionsImpl withMemberLookup(@Nullable MethodHandles.Lookup lookup) { 47 | return new BindingOptionsImpl(lookup); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/context/SelfTypeProxiedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.context; 26 | 27 | import dev.derklaro.aerogel.internal.PassThroughException; 28 | import org.apiguardian.api.API; 29 | 30 | /** 31 | * An exception thrown by an injection context that indicates that the type constructed by the current context was 32 | * proxied. The instance of this exception is jvm-static and the exception has neither a message, cause nor stack. 33 | * 34 | * @author Pasqual K. 35 | * @since 2.0 36 | */ 37 | @API(status = API.Status.INTERNAL, since = "2.0") 38 | final class SelfTypeProxiedException extends PassThroughException { 39 | 40 | /** 41 | * The jvm-static instance of this exception. 42 | */ 43 | public static final SelfTypeProxiedException INSTANCE = new SelfTypeProxiedException(); 44 | 45 | private SelfTypeProxiedException() { 46 | // we don't want anyone to construct this exception type directly 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /auto/src/processing/java/dev/derklaro/aerogel/auto/processing/AutoEntryProcessorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.processing; 26 | 27 | import javax.annotation.processing.ProcessingEnvironment; 28 | import org.apiguardian.api.API; 29 | import org.jetbrains.annotations.NotNull; 30 | 31 | /** 32 | * A factory for auto entry processors. The factories are discovered using SPI when the annotation processing 33 | * environment is initialized. 34 | * 35 | * @author Pasqual Koschmieder 36 | * @since 3.0 37 | */ 38 | @FunctionalInterface 39 | @API(status = API.Status.STABLE, since = "3.0") 40 | public interface AutoEntryProcessorFactory { 41 | 42 | /** 43 | * Constructs an auto entry processor for the given processing environment. 44 | * 45 | * @param environment the current annotation processing environment. 46 | * @return the constructed auto entry processor. 47 | */ 48 | @NotNull 49 | AutoEntryProcessor constructProcessor(@NotNull ProcessingEnvironment environment); 50 | } 51 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/annotation/Factory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.annotation; 26 | 27 | import java.lang.annotation.Documented; 28 | import java.lang.annotation.ElementType; 29 | import java.lang.annotation.Retention; 30 | import java.lang.annotation.RetentionPolicy; 31 | import java.lang.annotation.Target; 32 | import org.apiguardian.api.API; 33 | 34 | /** 35 | * An annotation that, when applied to a method, indicates that the method is a factory for the return type of the 36 | * annotated method. The method must pass all requirements of a factory method before being registered as one. 37 | * 38 | * @author Pasqual Koschmieder 39 | * @since 1.0 40 | */ 41 | @Documented 42 | @Target(ElementType.METHOD) 43 | @Retention(RetentionPolicy.RUNTIME) 44 | @API(status = API.Status.STABLE, since = "1.0") 45 | public @interface Factory { 46 | 47 | /** 48 | * Id of the codec to use when serializing or deserializing factory methods. 49 | */ 50 | String CODEC_ID = "factory"; 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/NullMaskTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.internal.util.NullMask; 28 | import org.junit.jupiter.api.Assertions; 29 | import org.junit.jupiter.api.Test; 30 | 31 | public class NullMaskTest { 32 | 33 | @Test 34 | void testMaskedValueIsProperlyUnmasked() { 35 | Object o = new Object(); 36 | Object masked = NullMask.mask(o); 37 | Assertions.assertNotNull(masked); 38 | Assertions.assertEquals(o, NullMask.unmask(masked)); 39 | 40 | Object masked2 = NullMask.mask(null); 41 | Assertions.assertNotNull(masked2); 42 | Assertions.assertNull(NullMask.unmask(masked2)); 43 | } 44 | 45 | @Test 46 | void testMaskedObjectIsDetected() { 47 | Object o = new Object(); 48 | Assertions.assertFalse(NullMask.masked(o)); 49 | 50 | Object masked1 = NullMask.mask(o); 51 | Assertions.assertFalse(NullMask.masked(masked1)); 52 | 53 | Object masked2 = NullMask.mask(null); 54 | Assertions.assertTrue(NullMask.masked(masked2)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/ProvidedBy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import java.lang.annotation.Documented; 28 | import java.lang.annotation.ElementType; 29 | import java.lang.annotation.Retention; 30 | import java.lang.annotation.RetentionPolicy; 31 | import java.lang.annotation.Target; 32 | import org.apiguardian.api.API; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | /** 36 | * Defines the implementation class for a type which will be used when a JIT binding is created. The annotation must be 37 | * present on the type that is being injected, not on the implementation type. 38 | * 39 | * @author Pasqual K. 40 | * @since 1.0 41 | */ 42 | @Documented 43 | @Target(ElementType.TYPE) 44 | @Retention(RetentionPolicy.RUNTIME) 45 | @API(status = API.Status.STABLE, since = "1.0") 46 | public @interface ProvidedBy { 47 | 48 | /** 49 | * Get the implementation class to which the annotated class is bound. 50 | * 51 | * @return the implementation class to which the annotated class is bound. 52 | */ 53 | @NotNull Class value(); 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/injector/InjectorBuilderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.injector; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.InjectorBuilder; 29 | import dev.derklaro.aerogel.binding.key.BindingKey; 30 | import java.lang.invoke.MethodHandles; 31 | import java.util.function.Predicate; 32 | import org.jetbrains.annotations.NotNull; 33 | 34 | public final class InjectorBuilderImpl implements InjectorBuilder { 35 | 36 | private InjectorOptions options = InjectorOptions.DEFAULT; 37 | 38 | @Override 39 | public @NotNull InjectorBuilder memberLookup(@NotNull MethodHandles.Lookup lookup) { 40 | this.options = this.options.withMemberLookup(lookup); 41 | return this; 42 | } 43 | 44 | @Override 45 | public @NotNull InjectorBuilder jitBindingFilter(@NotNull Predicate> filter) { 46 | this.options = this.options.withJitBindingFilter(filter); 47 | return this; 48 | } 49 | 50 | @Override 51 | public @NotNull Injector build() { 52 | return new InjectorImpl(this.options); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/internal/provides/ProvidesAutoEntryDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.internal.provides; 26 | 27 | import dev.derklaro.aerogel.auto.AutoEntryDecoder; 28 | import dev.derklaro.aerogel.auto.LazyBindingCollection; 29 | import dev.derklaro.aerogel.auto.annotation.Provides; 30 | import dev.derklaro.aerogel.auto.internal.util.AutoDecodingUtil; 31 | import java.io.DataInput; 32 | import java.io.IOException; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | public final class ProvidesAutoEntryDecoder implements AutoEntryDecoder { 36 | 37 | @Override 38 | public @NotNull String id() { 39 | return Provides.CODEC_ID; 40 | } 41 | 42 | @Override 43 | public @NotNull LazyBindingCollection decodeEntry( 44 | @NotNull DataInput dataInput, 45 | @NotNull ClassLoader loader 46 | ) throws IOException { 47 | Class implementation = AutoDecodingUtil.decodeType(dataInput, loader); 48 | Class[] providedTypes = AutoDecodingUtil.decodeTypes(dataInput, loader); 49 | return new ProvidesLazyBindingCollection(implementation, providedTypes); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/annotation/Provides.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.annotation; 26 | 27 | import java.lang.annotation.Documented; 28 | import java.lang.annotation.ElementType; 29 | import java.lang.annotation.Retention; 30 | import java.lang.annotation.RetentionPolicy; 31 | import java.lang.annotation.Target; 32 | import org.apiguardian.api.API; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | /** 36 | * An annotation that, when applied to a type, indicates which type implementations are provided by the annotated type. 37 | * 38 | * @author Pasqual Koschmieder 39 | * @since 1.0 40 | */ 41 | @Documented 42 | @Target(ElementType.TYPE) 43 | @Retention(RetentionPolicy.RUNTIME) 44 | @API(status = API.Status.STABLE, since = "1.0") 45 | public @interface Provides { 46 | 47 | /** 48 | * Id of the codec to use when serializing or deserializing provided annotated types. 49 | */ 50 | String CODEC_ID = "provides"; 51 | 52 | /** 53 | * Get the types that are implemented by the annotated type. 54 | * 55 | * @return the types that are implemented by the annotated type. 56 | */ 57 | @NotNull Class[] value(); 58 | } 59 | -------------------------------------------------------------------------------- /auto/src/processing/java/dev/derklaro/aerogel/auto/processing/internal/util/AutoTypeEncodingUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.processing.internal.util; 26 | 27 | import java.util.Collections; 28 | import java.util.List; 29 | import javax.lang.model.type.MirroredTypeException; 30 | import javax.lang.model.type.MirroredTypesException; 31 | import javax.lang.model.type.TypeMirror; 32 | import org.jetbrains.annotations.NotNull; 33 | 34 | public final class AutoTypeEncodingUtil { 35 | 36 | private AutoTypeEncodingUtil() { 37 | throw new UnsupportedOperationException(); 38 | } 39 | 40 | public static @NotNull List getTypesFromAnnotationProperty(@NotNull Runnable extractor) { 41 | try { 42 | extractor.run(); 43 | throw new IllegalStateException("Extractor did not access type(s) from annotation property"); 44 | } catch (MirroredTypeException exception) { 45 | // single type was mirrored (Class) 46 | return Collections.singletonList(exception.getTypeMirror()); 47 | } catch (MirroredTypesException exception) { 48 | // multiple types were mirrored (Class[]) 49 | return exception.getTypeMirrors(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/binding/ProviderWithContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.binding; 26 | 27 | import dev.derklaro.aerogel.internal.context.InjectionContext; 28 | import org.apiguardian.api.API; 29 | import org.jetbrains.annotations.NotNull; 30 | import org.jetbrains.annotations.Nullable; 31 | 32 | /** 33 | * Provides instances of {@code T} while also taking the current injection context into account. Mainly used for 34 | * internal instance construction, external users should use {@link jakarta.inject.Provider}s from the target binding 35 | * instead. Note: unlike providers, this type cannot be injected. 36 | * 37 | * @param the type being provided by this provider. 38 | * @author Pasqual Koschmieder 39 | * @since 3.0 40 | */ 41 | @FunctionalInterface 42 | @API(status = API.Status.MAINTAINED, since = "3.0") 43 | public interface ProviderWithContext { 44 | 45 | /** 46 | * Provides a fully constructed value of {@code T} with respect to the given injection context. 47 | * 48 | * @param context the current injection context. 49 | * @return a fully constructed value of {@code T}. 50 | */ 51 | @Nullable 52 | T get(@NotNull InjectionContext context); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/binding/BindingOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.binding; 26 | 27 | import java.lang.invoke.MethodHandles; 28 | import java.util.Optional; 29 | import org.apiguardian.api.API; 30 | import org.jetbrains.annotations.NotNull; 31 | 32 | /** 33 | * Advanced options that can be configured when building a binding. Settings these options is not strictly required for 34 | * the injection process to work, however, the injection process can be configured as needed using these options. 35 | * 36 | * @author Pasqual Koschmieder 37 | * @since 3.0 38 | */ 39 | @API(status = API.Status.STABLE, since = "3.0") 40 | public interface BindingOptions { 41 | 42 | /** 43 | * Defines the lookup that should be used to access members in the classes that is targeted by the associated binding. 44 | * This can be the injectable constructor, fields and methods. If not defined, the public lookup will be used which 45 | * can lead to access errors due to limited member visibility. 46 | * 47 | * @return the lookup that should be used to access members in the classes that is targeted by the associated binding. 48 | */ 49 | @NotNull 50 | Optional memberLookup(); 51 | } 52 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/aerogel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 41 | -------------------------------------------------------------------------------- /auto/src/test/java/dev/derklaro/aerogel/auto/util/TestJavaClassBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.util; 26 | 27 | import com.squareup.javapoet.FieldSpec; 28 | import com.squareup.javapoet.JavaFile; 29 | import com.squareup.javapoet.MethodSpec; 30 | import com.squareup.javapoet.TypeSpec; 31 | import javax.tools.JavaFileObject; 32 | 33 | public final class TestJavaClassBuilder { 34 | 35 | private final TypeSpec.Builder typeSpec; 36 | 37 | private TestJavaClassBuilder(TypeSpec.Builder typeSpec) { 38 | this.typeSpec = typeSpec; 39 | } 40 | 41 | public static TestJavaClassBuilder of(String className) { 42 | return new TestJavaClassBuilder(TypeSpec.classBuilder(className)); 43 | } 44 | 45 | public static TestJavaClassBuilder from(TypeSpec.Builder typeSpec) { 46 | return new TestJavaClassBuilder(typeSpec); 47 | } 48 | 49 | public TestJavaClassBuilder withField(FieldSpec.Builder spec) { 50 | this.typeSpec.addField(spec.build()); 51 | return this; 52 | } 53 | 54 | public TestJavaClassBuilder withMethod(MethodSpec.Builder spec) { 55 | this.typeSpec.addMethod(spec.build()); 56 | return this; 57 | } 58 | 59 | public JavaFileObject build() { 60 | return this.build(""); 61 | } 62 | 63 | public JavaFileObject build(String packageName) { 64 | return JavaFile.builder(packageName, this.typeSpec.build()) 65 | .build() 66 | .toJavaFileObject(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/context/scope/InjectionContextScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.context.scope; 26 | 27 | import dev.derklaro.aerogel.internal.context.InjectionContext; 28 | import java.util.function.Supplier; 29 | import org.apiguardian.api.API; 30 | import org.jetbrains.annotations.NotNull; 31 | import org.jetbrains.annotations.UnknownNullability; 32 | 33 | /** 34 | * A scope of an injection context returned by a context provider. 35 | * 36 | * @author Pasqual K. 37 | * @since 3.0 38 | */ 39 | @API(status = API.Status.INTERNAL, since = "3.0") 40 | public interface InjectionContextScope { 41 | 42 | /** 43 | * The context that is wrapped by this context scope. 44 | * 45 | * @return the wrapped injection context. 46 | */ 47 | @NotNull 48 | InjectionContext context(); 49 | 50 | /** 51 | * Executes the given operation using the injection context of this scope. This method overrides the current scoped 52 | * context for the lifetime of the operation and resets it to the previous value afterward. 53 | * 54 | * @param operation the operation to execute. 55 | * @param the type of value returned by the given operation. 56 | * @return the value returned by the given operation. 57 | * @throws NullPointerException if the given operation is null. 58 | */ 59 | @UnknownNullability 60 | T executeScoped(@NotNull Supplier operation); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/Order.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import java.lang.annotation.Documented; 28 | import java.lang.annotation.ElementType; 29 | import java.lang.annotation.Retention; 30 | import java.lang.annotation.RetentionPolicy; 31 | import java.lang.annotation.Target; 32 | import org.apiguardian.api.API; 33 | 34 | /** 35 | * The order annotation can be used to configure the order in which method injection happens. If the annotation is not 36 | * defined the {@link Order#DEFAULT} value will be applied to the element. If multiple elements have the same order, the 37 | * methods are compared based on their name. 38 | * 39 | * @author Pasqual K. 40 | * @since 2.0 41 | */ 42 | @Documented 43 | @Target(ElementType.METHOD) 44 | @Retention(RetentionPolicy.RUNTIME) 45 | @API(status = API.Status.STABLE, since = "2.0") 46 | public @interface Order { 47 | 48 | /** 49 | * The default order applied to injectable methods which are not annotated with an explicit order. 50 | */ 51 | int DEFAULT = Integer.MAX_VALUE / 2; 52 | 53 | /** 54 | * The order value for the annotated injectable method. Elements are ordered based on priority where a lower value has 55 | * greater priority than a higher value. For example, {@link Integer#MAX_VALUE} has a lower priority than 56 | * {@code 100}. 57 | * 58 | * @return the order of the annotated injectable method. 59 | */ 60 | int value(); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/binding/DynamicBindingImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.binding; 26 | 27 | import dev.derklaro.aerogel.binding.DynamicBinding; 28 | import dev.derklaro.aerogel.binding.UninstalledBinding; 29 | import dev.derklaro.aerogel.binding.key.BindingKey; 30 | import java.util.Optional; 31 | import java.util.function.Function; 32 | import java.util.function.Predicate; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | public final class DynamicBindingImpl implements DynamicBinding { 36 | 37 | private final Predicate> filter; 38 | private final Function, UninstalledBinding> bindingFactory; 39 | 40 | public DynamicBindingImpl( 41 | @NotNull Predicate> filter, 42 | @NotNull Function, UninstalledBinding> bindingFactory 43 | ) { 44 | this.filter = filter; 45 | this.bindingFactory = bindingFactory; 46 | } 47 | 48 | @Override 49 | public boolean supports(@NotNull BindingKey key) { 50 | return this.filter.test(key); 51 | } 52 | 53 | @Override 54 | @SuppressWarnings("unchecked") 55 | public @NotNull Optional> tryMatch(@NotNull BindingKey key) { 56 | if (this.filter.test(key)) { 57 | UninstalledBinding binding = (UninstalledBinding) this.bindingFactory.apply(key); 58 | return Optional.ofNullable(binding); 59 | } else { 60 | return Optional.empty(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/binding/builder/AdvancedBindingBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.binding.builder; 26 | 27 | import java.lang.invoke.MethodHandles; 28 | import org.apiguardian.api.API; 29 | import org.jetbrains.annotations.NotNull; 30 | 31 | /** 32 | * Builder step that allows to set advanced options for the target binding. Settings these options is not required, but 33 | * might enable some extra behaviour or might be even required for the injection process to work as expected. 34 | * 35 | * @param the type of values handled by this binding that is being built. 36 | * @author Pasqual Koschmieder 37 | * @since 3.0 38 | */ 39 | @API(status = API.Status.STABLE, since = "3.0") 40 | public interface AdvancedBindingBuilder extends TargetableBindingBuilder { 41 | 42 | /** 43 | * Sets the lookup instance that should be used to get access to members in the target implementation class during 44 | * injection. This is especially useful when, for example, modules are used and class member visibility is blocked to 45 | * the injector. The provided lookup will be used for every operation that includes reflective access (constructor, 46 | * method and field injection). 47 | * 48 | * @param lookup the lookup to use for reflective operations on members related to the binding. 49 | * @return this builder, for chaining or finishing the binding process. 50 | */ 51 | @NotNull 52 | AdvancedBindingBuilder memberLookup(@NotNull MethodHandles.Lookup lookup); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/context/UnbreakableCyclicDependencyException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.context; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.internal.PassThroughException; 29 | import java.util.Arrays; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | /** 34 | * Exception thrown when a cyclic dependency gets detected during construction. 35 | * 36 | * @author Pasqual Koschmieder 37 | * @since 2.0 38 | */ 39 | @API(status = API.Status.INTERNAL, since = "3.0") 40 | final class UnbreakableCyclicDependencyException extends PassThroughException { 41 | 42 | /** 43 | * The package name to filter from the exception stack trace. 44 | */ 45 | private static final String PACKAGE_PREFIX = Injector.class.getPackageName(); 46 | 47 | public UnbreakableCyclicDependencyException(@NotNull String message) { 48 | super(message); 49 | 50 | // filter and set the stack trace of the exception 51 | StackTraceElement[] currentThreadStack = new RuntimeException().getStackTrace(); 52 | for (int index = 0; index < currentThreadStack.length; index++) { 53 | StackTraceElement traceElement = currentThreadStack[index]; 54 | if (!traceElement.getClassName().startsWith(PACKAGE_PREFIX)) { 55 | StackTraceElement[] relevantStack = Arrays.copyOfRange(currentThreadStack, index, currentThreadStack.length); 56 | this.setStackTrace(relevantStack); 57 | break; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/injector/InjectorOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.injector; 26 | 27 | import dev.derklaro.aerogel.binding.key.BindingKey; 28 | import java.lang.invoke.MethodHandles; 29 | import java.util.function.Predicate; 30 | import org.jetbrains.annotations.NotNull; 31 | 32 | final class InjectorOptions { 33 | 34 | static final InjectorOptions DEFAULT = new InjectorOptions(MethodHandles.lookup(), $ -> true); 35 | 36 | private final MethodHandles.Lookup memberLookup; 37 | private final Predicate> jitBindingFilter; 38 | 39 | private InjectorOptions( 40 | @NotNull MethodHandles.Lookup memberLookup, 41 | @NotNull Predicate> jitBindingFilter 42 | ) { 43 | this.memberLookup = memberLookup; 44 | this.jitBindingFilter = jitBindingFilter; 45 | } 46 | 47 | public @NotNull MethodHandles.Lookup memberLookup() { 48 | return this.memberLookup; 49 | } 50 | 51 | public boolean shouldConstructJitBinding(@NotNull BindingKey key) { 52 | return this.jitBindingFilter.test(key); 53 | } 54 | 55 | public @NotNull InjectorOptions withMemberLookup(@NotNull MethodHandles.Lookup memberLookup) { 56 | return this.memberLookup == memberLookup ? this : new InjectorOptions(memberLookup, this.jitBindingFilter); 57 | } 58 | 59 | public @NotNull InjectorOptions withJitBindingFilter(@NotNull Predicate> jitBindingFilter) { 60 | return this.jitBindingFilter == jitBindingFilter ? this : new InjectorOptions(this.memberLookup, jitBindingFilter); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/internal/CombinedLazyBindingCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.internal; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.auto.LazyBindingCollection; 29 | import dev.derklaro.aerogel.binding.UninstalledBinding; 30 | import java.util.ArrayList; 31 | import java.util.Collections; 32 | import java.util.List; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | public final class CombinedLazyBindingCollection implements LazyBindingCollection { 36 | 37 | private final LazyBindingCollection left; 38 | private final LazyBindingCollection right; 39 | 40 | public CombinedLazyBindingCollection(@NotNull LazyBindingCollection left, @NotNull LazyBindingCollection right) { 41 | this.left = left; 42 | this.right = right; 43 | } 44 | 45 | @Override 46 | public void installBindings(@NotNull Injector injector) { 47 | this.left.installBindings(injector); 48 | this.right.installBindings(injector); 49 | } 50 | 51 | @Override 52 | public @NotNull List> constructBindings(@NotNull Injector injector) { 53 | List> bindings = new ArrayList<>(); 54 | bindings.addAll(this.left.constructBindings(injector)); 55 | bindings.addAll(this.right.constructBindings(injector)); 56 | return Collections.unmodifiableList(bindings); 57 | } 58 | 59 | @Override 60 | public @NotNull LazyBindingCollection combine(@NotNull LazyBindingCollection other) { 61 | return new CombinedLazyBindingCollection(this, other); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/provider/DelegatingProviderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.provider; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import dev.derklaro.aerogel.internal.context.InjectionContext; 29 | import jakarta.inject.Provider; 30 | import org.jetbrains.annotations.NotNull; 31 | import org.jetbrains.annotations.Nullable; 32 | 33 | public final class DelegatingProviderFactory implements ProviderFactory { 34 | 35 | private final Provider delegate; 36 | 37 | private DelegatingProviderFactory(@NotNull Provider delegate) { 38 | this.delegate = delegate; 39 | } 40 | 41 | public static @NotNull DelegatingProviderFactory toProvider(@NotNull Provider delegate) { 42 | return new DelegatingProviderFactory<>(delegate); 43 | } 44 | 45 | @Override 46 | public @NotNull ProviderWithContext constructProvider() { 47 | return new DelegatingProvider<>(this.delegate); 48 | } 49 | 50 | private static final class DelegatingProvider implements ProviderWithContext { 51 | 52 | private final Provider delegate; 53 | 54 | public DelegatingProvider(@NotNull Provider delegate) { 55 | this.delegate = delegate; 56 | } 57 | 58 | @Override 59 | public @Nullable T get(@NotNull InjectionContext context) { 60 | return this.delegate.get(); 61 | } 62 | 63 | @Override 64 | public @NotNull String toString() { 65 | return "Delegating(" + this.delegate + ")"; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/util/PrimitiveUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.util; 26 | 27 | import org.jetbrains.annotations.NotNull; 28 | 29 | public final class PrimitiveUtil { 30 | 31 | // valueOf for other primitive types are cached, double & float will always produce a new instance 32 | private static final Float FLOAT_DEFAULT = 0F; 33 | private static final Double DOUBLE_DEFAULT = 0D; 34 | 35 | private PrimitiveUtil() { 36 | throw new UnsupportedOperationException(); 37 | } 38 | 39 | /** 40 | * Gets the default value of the given {@code type}. 41 | * 42 | * @param type the type to get. 43 | * @param the wildcard type of the class to get. 44 | * @return the default initialization value of the associated primitive type. 45 | */ 46 | @SuppressWarnings("unchecked") 47 | public static @NotNull T defaultValue(@NotNull Class type) { 48 | if (type == boolean.class) { 49 | return (T) Boolean.FALSE; 50 | } else if (type == char.class) { 51 | return (T) Character.valueOf('\0'); 52 | } else if (type == byte.class) { 53 | return (T) Byte.valueOf((byte) 0); 54 | } else if (type == short.class) { 55 | return (T) Short.valueOf((short) 0); 56 | } else if (type == int.class) { 57 | return (T) Integer.valueOf(0); 58 | } else if (type == long.class) { 59 | return (T) Long.valueOf(0L); 60 | } else if (type == float.class) { 61 | return (T) FLOAT_DEFAULT; 62 | } else if (type == double.class) { 63 | return (T) DOUBLE_DEFAULT; 64 | } else { 65 | // cannot reach 66 | throw new AssertionError(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/PassThroughException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal; 26 | 27 | import org.apiguardian.api.API; 28 | import org.jetbrains.annotations.NotNull; 29 | import org.jetbrains.annotations.Nullable; 30 | 31 | /** 32 | * Represents an exception which, when caught, should be rethrown as-is without further wrapping. This exception type 33 | * has never a stacktrace available. 34 | * 35 | * @since 2.0 36 | */ 37 | @API(status = API.Status.INTERNAL, since = "2.0") 38 | public class PassThroughException extends RuntimeException { 39 | 40 | /** 41 | * Constructs a new instance of this exception, protected to ensure that only overrides are possible. 42 | */ 43 | protected PassThroughException() { 44 | } 45 | 46 | /** 47 | * Constructs a new instance of this exception, protected to ensure that only overrides are possible. 48 | * 49 | * @param cause the cause which should be available for later retrieval. 50 | */ 51 | protected PassThroughException(@NotNull Throwable cause) { 52 | super(cause); 53 | } 54 | 55 | /** 56 | * Constructs a new instance of this exception, protected to ensure that only overrides are possible. 57 | * 58 | * @param message the message describing why the exception occurred. 59 | */ 60 | protected PassThroughException(@NotNull String message) { 61 | super(message); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public @NotNull Throwable fillInStackTrace() { 69 | return this; 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | public @NotNull Throwable initCause(@Nullable Throwable cause) { 77 | return this; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/provider/DelegatingContextualProviderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.provider; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import dev.derklaro.aerogel.internal.context.InjectionContext; 29 | import org.jetbrains.annotations.NotNull; 30 | import org.jetbrains.annotations.Nullable; 31 | 32 | public final class DelegatingContextualProviderFactory implements ProviderFactory { 33 | 34 | private final ProviderWithContext delegate; 35 | 36 | private DelegatingContextualProviderFactory(@NotNull ProviderWithContext delegate) { 37 | this.delegate = delegate; 38 | } 39 | 40 | public static @NotNull DelegatingContextualProviderFactory toProvider( 41 | @NotNull ProviderWithContext delegate 42 | ) { 43 | return new DelegatingContextualProviderFactory<>(delegate); 44 | } 45 | 46 | @Override 47 | public @NotNull ProviderWithContext constructProvider() { 48 | return new DelegatingContextualProvider<>(this.delegate); 49 | } 50 | 51 | private static final class DelegatingContextualProvider implements ProviderWithContext { 52 | 53 | private final ProviderWithContext delegate; 54 | 55 | public DelegatingContextualProvider(@NotNull ProviderWithContext delegate) { 56 | this.delegate = delegate; 57 | } 58 | 59 | @Override 60 | public @Nullable T get(@NotNull InjectionContext context) { 61 | return this.delegate.get(context); 62 | } 63 | 64 | @Override 65 | public @NotNull String toString() { 66 | return "DelegatingContextual(" + this.delegate + ")"; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/provider/CascadingProviderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.provider; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import dev.derklaro.aerogel.binding.key.BindingKey; 29 | import dev.derklaro.aerogel.internal.context.InjectionContext; 30 | import jakarta.inject.Provider; 31 | import org.jetbrains.annotations.NotNull; 32 | import org.jetbrains.annotations.Nullable; 33 | 34 | public final class CascadingProviderFactory implements ProviderFactory { 35 | 36 | private final BindingKey cascadedTo; 37 | 38 | private CascadingProviderFactory(@NotNull BindingKey cascadedTo) { 39 | this.cascadedTo = cascadedTo; 40 | } 41 | 42 | public static @NotNull CascadingProviderFactory cascadeTo(@NotNull BindingKey cascadedTo) { 43 | return new CascadingProviderFactory<>(cascadedTo); 44 | } 45 | 46 | @Override 47 | public @NotNull ProviderWithContext constructProvider() { 48 | return new CascadedProvider<>(this.cascadedTo); 49 | } 50 | 51 | private static final class CascadedProvider implements ProviderWithContext { 52 | 53 | private final BindingKey cascadedTo; 54 | 55 | public CascadedProvider(@NotNull BindingKey cascadedTo) { 56 | this.cascadedTo = cascadedTo; 57 | } 58 | 59 | @Override 60 | public @Nullable T get(@NotNull InjectionContext context) { 61 | Provider provider = context.injector().provider(this.cascadedTo); 62 | return provider.get(); 63 | } 64 | 65 | @Override 66 | public @NotNull String toString() { 67 | return "Cascaded(" + this.cascadedTo + ")"; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/SingletonCircularTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.binding.UninstalledBinding; 28 | import dev.derklaro.aerogel.binding.builder.RootBindingBuilder; 29 | import jakarta.inject.Inject; 30 | import jakarta.inject.Singleton; 31 | import java.util.concurrent.atomic.AtomicInteger; 32 | import org.junit.jupiter.api.Assertions; 33 | import org.junit.jupiter.api.Test; 34 | 35 | public class SingletonCircularTest { 36 | 37 | @Test 38 | void testSingletonKeptOnDuplicateCircularDependency() { 39 | Injector injector = Injector.newInjector(); 40 | RootBindingBuilder bindingBuilder = injector.createBindingBuilder(); 41 | UninstalledBinding aItfBinding = bindingBuilder.bind(AItf1.class).toConstructingClass(AItf1Impl.class); 42 | injector.installBinding(aItfBinding); 43 | 44 | Assertions.assertDoesNotThrow(() -> injector.instance(AItf1.class)); 45 | Assertions.assertEquals(1, A_IMPL_INIT_CALLS.get()); 46 | Assertions.assertEquals(2, NON_A_IMPL_INIT_CALLS.get()); 47 | } 48 | 49 | // @formatter:off 50 | private static final AtomicInteger A_IMPL_INIT_CALLS = new AtomicInteger(0); 51 | private static final AtomicInteger NON_A_IMPL_INIT_CALLS = new AtomicInteger(0); 52 | public interface AItf1 {} 53 | @Singleton public static class AItf1Impl implements AItf1 { 54 | @Inject public AItf1Impl(BImpl b, CImpl c) { A_IMPL_INIT_CALLS.incrementAndGet(); } 55 | } 56 | public static class BImpl { 57 | @Inject public BImpl(AItf1 aItf1) { NON_A_IMPL_INIT_CALLS.incrementAndGet(); } 58 | } 59 | public static class CImpl { 60 | @Inject public CImpl(AItf1 aItf1) { NON_A_IMPL_INIT_CALLS.incrementAndGet(); } 61 | } 62 | // @formatter:on 63 | } 64 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/internal/factory/FactoryLazyBindingCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.internal.factory; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.auto.LazyBindingCollection; 29 | import dev.derklaro.aerogel.auto.internal.CombinedLazyBindingCollection; 30 | import dev.derklaro.aerogel.binding.UninstalledBinding; 31 | import dev.derklaro.aerogel.binding.key.BindingKey; 32 | import java.lang.reflect.Method; 33 | import java.util.Collections; 34 | import java.util.List; 35 | import org.jetbrains.annotations.NotNull; 36 | 37 | final class FactoryLazyBindingCollection implements LazyBindingCollection { 38 | 39 | private final BindingKey key; 40 | private final Method factoryMethod; 41 | 42 | public FactoryLazyBindingCollection(@NotNull BindingKey key, @NotNull Method factoryMethod) { 43 | this.key = key; 44 | this.factoryMethod = factoryMethod; 45 | } 46 | 47 | @Override 48 | public void installBindings(@NotNull Injector injector) { 49 | UninstalledBinding binding = this.makeBinding(injector); 50 | injector.installBinding(binding); 51 | } 52 | 53 | @Override 54 | public @NotNull List> constructBindings(@NotNull Injector injector) { 55 | UninstalledBinding binding = this.makeBinding(injector); 56 | return Collections.singletonList(binding); 57 | } 58 | 59 | @Override 60 | public @NotNull LazyBindingCollection combine(@NotNull LazyBindingCollection other) { 61 | return new CombinedLazyBindingCollection(this, other); 62 | } 63 | 64 | private @NotNull UninstalledBinding makeBinding(@NotNull Injector injector) { 65 | return injector.createBindingBuilder().bind(this.key).toFactoryMethod(this.factoryMethod); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/AutoEntryDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto; 26 | 27 | import java.io.DataInput; 28 | import java.io.IOException; 29 | import org.apiguardian.api.API; 30 | import org.jetbrains.annotations.NotNull; 31 | 32 | /** 33 | * A decoder for auto entries. A decoder can either be registered automatically via SPI or manually by registering it 34 | * into the registry of the target module. 35 | * 36 | * @author Pasqual Koschmieder 37 | * @since 3.0 38 | */ 39 | @API(status = API.Status.STABLE, since = "3.0") 40 | public interface AutoEntryDecoder { 41 | 42 | /** 43 | * Get the unique identifier of this auto entry decoder. A decoder is called based on the id written into the given 44 | * input data stream (each entry must be prefixed with the decoder id to use). 45 | * 46 | * @return the unique identifier of this auto entry decoder. 47 | */ 48 | @NotNull 49 | String id(); 50 | 51 | /** 52 | * Decodes an entry based on the given data input. This decoder must make sure to read all the data that was written 53 | * during serialization so that the cursor position is at the head for the next deserialization step. 54 | * 55 | * @param dataInput the data input to read the necessary information from to decode the entry. 56 | * @param loader the class loader to use when decoding types. 57 | * @return a collection of entries that were decoded from the given data input. 58 | * @throws IOException if an I/O error occurs while reading from the given data input. 59 | * @throws IllegalStateException in case something goes wrong during binding deserialization. 60 | */ 61 | @NotNull 62 | LazyBindingCollection decodeEntry(@NotNull DataInput dataInput, @NotNull ClassLoader loader) throws IOException; 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/AnnotationUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.internal.annotation.AnnotationUtil; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import org.junit.jupiter.api.Assertions; 31 | import org.junit.jupiter.api.Test; 32 | 33 | public class AnnotationUtilTest { 34 | 35 | @Test 36 | void testHasProperties() { 37 | Assertions.assertFalse(AnnotationUtil.hasProperties(AnnotationWithoutMember.class)); 38 | Assertions.assertTrue(AnnotationUtil.hasProperties(AnnotationWithMember.class)); 39 | Assertions.assertTrue(AnnotationUtil.hasProperties(AnnotationWithMultipleMembers.class)); 40 | } 41 | 42 | @Test 43 | void testExtractRetention() { 44 | Assertions.assertEquals(RetentionPolicy.CLASS, AnnotationUtil.extractRetention(AnnotationRetClass.class)); 45 | Assertions.assertEquals(RetentionPolicy.SOURCE, AnnotationUtil.extractRetention(AnnotationRetSource.class)); 46 | Assertions.assertEquals(RetentionPolicy.RUNTIME, AnnotationUtil.extractRetention(AnnotationRetRuntime.class)); 47 | } 48 | 49 | // @formatter:off 50 | @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationWithoutMember {} 51 | @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationWithMember { 52 | String value(); 53 | } 54 | @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationWithMultipleMembers { 55 | String value(); 56 | Class value2(); 57 | int value3(); 58 | } 59 | @Retention(RetentionPolicy.CLASS) public @interface AnnotationRetClass {} 60 | @Retention(RetentionPolicy.SOURCE) public @interface AnnotationRetSource {} 61 | @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationRetRuntime {} 62 | // @formatter:on 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/PrimitiveUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.internal.util.PrimitiveUtil; 28 | import java.util.Collection; 29 | import org.junit.jupiter.api.Assertions; 30 | import org.junit.jupiter.api.Test; 31 | 32 | public class PrimitiveUtilTest { 33 | 34 | @Test 35 | void testDefaultBoolean() { 36 | Assertions.assertFalse(PrimitiveUtil.defaultValue(boolean.class)); 37 | } 38 | 39 | @Test 40 | void testDefaultChar() { 41 | Assertions.assertEquals('\0', PrimitiveUtil.defaultValue(char.class)); 42 | } 43 | 44 | @Test 45 | void testDefaultByte() { 46 | Assertions.assertEquals((byte) 0, PrimitiveUtil.defaultValue(byte.class)); 47 | } 48 | 49 | @Test 50 | void testDefaultShort() { 51 | Assertions.assertEquals((short) 0, PrimitiveUtil.defaultValue(short.class)); 52 | } 53 | 54 | @Test 55 | void testDefaultInt() { 56 | Assertions.assertEquals(0, PrimitiveUtil.defaultValue(int.class)); 57 | } 58 | 59 | @Test 60 | void testDefaultLong() { 61 | Assertions.assertEquals(0L, PrimitiveUtil.defaultValue(long.class)); 62 | } 63 | 64 | @Test 65 | void testDefaultFloat() { 66 | Assertions.assertEquals(0f, PrimitiveUtil.defaultValue(float.class)); 67 | } 68 | 69 | @Test 70 | void testDefaultDouble() { 71 | Assertions.assertEquals(0d, PrimitiveUtil.defaultValue(double.class)); 72 | } 73 | 74 | @Test 75 | void testNonPrimitiveTypeThrowsException() { 76 | Assertions.assertThrows(AssertionError.class, () -> PrimitiveUtil.defaultValue(Object.class)); 77 | Assertions.assertThrows(AssertionError.class, () -> PrimitiveUtil.defaultValue(String.class)); 78 | Assertions.assertThrows(AssertionError.class, () -> PrimitiveUtil.defaultValue(Collection.class)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/CircularMemberInjectionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.binding.UninstalledBinding; 28 | import jakarta.inject.Inject; 29 | import jakarta.inject.Named; 30 | import jakarta.inject.Singleton; 31 | import org.junit.jupiter.api.Assertions; 32 | import org.junit.jupiter.api.Test; 33 | 34 | public class CircularMemberInjectionTest { 35 | 36 | @Test 37 | void testCircularMemberInjection() { 38 | Injector injector = Injector.newInjector(); 39 | 40 | UninstalledBinding testStringBinding = injector.createBindingBuilder() 41 | .bind(String.class) 42 | .qualifiedWithName("test") 43 | .toInstance("Hello World"); 44 | injector.installBinding(testStringBinding); 45 | 46 | SomeClass instance = Assertions.assertDoesNotThrow(() -> injector.instance(SomeClass.class)); 47 | Assertions.assertNotNull(instance); 48 | Assertions.assertEquals("Hello World", instance.helloWorld); 49 | Assertions.assertNotNull(instance.someOtherClass); 50 | Assertions.assertSame(instance, instance.someOtherClass.someClass); 51 | } 52 | 53 | @Singleton 54 | private static final class SomeClass { 55 | 56 | private final String helloWorld; 57 | private SomeOtherClass someOtherClass; 58 | 59 | @Inject 60 | public SomeClass(@Named("test") String helloWorld) { 61 | this.helloWorld = helloWorld; 62 | } 63 | 64 | @Inject 65 | public void constructDone(SomeOtherClass otherClass) { 66 | this.someOtherClass = otherClass; 67 | } 68 | } 69 | 70 | @Singleton 71 | private static final class SomeOtherClass { 72 | 73 | private final SomeClass someClass; 74 | 75 | @Inject 76 | public SomeOtherClass(SomeClass someClass) { 77 | this.someClass = someClass; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /scoped-value-context-scope/src/main/java/dev/derklaro/aerogel/scopedvalue/ScopedValueInjectionContextScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.scopedvalue; 26 | 27 | import dev.derklaro.aerogel.internal.context.InjectionContext; 28 | import dev.derklaro.aerogel.internal.context.scope.InjectionContextScope; 29 | import java.util.function.Supplier; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.NotNull; 32 | import org.jetbrains.annotations.UnknownNullability; 33 | 34 | /** 35 | * A context scope that uses scope value carries to set the scope during injection. 36 | * 37 | * @author Pasqual K. 38 | * @since 3.0 39 | */ 40 | @API(status = API.Status.INTERNAL, since = "3.0") 41 | final class ScopedValueInjectionContextScope implements InjectionContextScope { 42 | 43 | private final InjectionContext context; 44 | private final ScopedValue.Carrier contextScopeCarrier; 45 | 46 | /** 47 | * Constructs a new injection context scope for the given context and scoped value. 48 | * 49 | * @param context the context that is bound to this scope. 50 | * @param scopeScopedValue the scoped value for the injection scopes. 51 | */ 52 | public ScopedValueInjectionContextScope( 53 | @NotNull InjectionContext context, 54 | @NotNull ScopedValue scopeScopedValue 55 | ) { 56 | this.context = context; 57 | this.contextScopeCarrier = ScopedValue.where(scopeScopedValue, this); 58 | } 59 | 60 | /** 61 | * {@inheritDoc} 62 | */ 63 | @Override 64 | public @NotNull InjectionContext context() { 65 | return this.context; 66 | } 67 | 68 | /** 69 | * {@inheritDoc} 70 | */ 71 | @Override 72 | public @UnknownNullability T executeScoped(@NotNull Supplier operation) { 73 | return this.contextScopeCarrier.call(operation::get); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/LazyBindingCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.binding.UninstalledBinding; 29 | import java.util.List; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.Contract; 32 | import org.jetbrains.annotations.NotNull; 33 | 34 | /** 35 | * A collection of bindings that are lazily constructed for a given injector. 36 | * 37 | * @author Pasqual Koschmieder 38 | * @since 3.0 39 | */ 40 | @API(status = API.Status.STABLE, since = "3.0") 41 | public interface LazyBindingCollection { 42 | 43 | /** 44 | * Installs the bindings that are located in this collection directly into the given injector. 45 | * 46 | * @param injector the injector to construct the bindings for and install into. 47 | */ 48 | void installBindings(@NotNull Injector injector); 49 | 50 | /** 51 | * Constructs all bindings for the given injector and returns them for further handling by the caller. There is no 52 | * guarantee that the returned list is mutable. 53 | * 54 | * @param injector the injector to construct the bindings for. 55 | * @return the uninstalled bindings that were constructed for the given injector. 56 | */ 57 | @NotNull 58 | List> constructBindings(@NotNull Injector injector); 59 | 60 | /** 61 | * Combines this binding collection with the given other binding collection. Calls to the returned new binding 62 | * collection will return a combined result. 63 | * 64 | * @param other the binding collection to combine with this binding collection. 65 | * @return a new binding collection which executes all calls on this and the other binding collection. 66 | */ 67 | @NotNull 68 | @Contract("_ -> new") 69 | LazyBindingCollection combine(@NotNull LazyBindingCollection other); 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/TargetedInjectorBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.binding.UninstalledBinding; 28 | import org.apiguardian.api.API; 29 | import org.jetbrains.annotations.Contract; 30 | import org.jetbrains.annotations.NotNull; 31 | 32 | /** 33 | * A builder for an injector which only has very specific bindings present, and does not allow binding registration 34 | * during runtime. This means that bindings created by a targeted injector have access to specific bindings, but are 35 | * registered into the parent injector. 36 | *

37 | * An example use case could be a module system which needs configuration bindings for the current module, but wants to 38 | * allow modules to access classes defined in other modules. 39 | * 40 | * @author Pasqual Koschmieder 41 | * @since 3.0 42 | */ 43 | @API(status = API.Status.STABLE, since = "3.0") 44 | public interface TargetedInjectorBuilder { 45 | 46 | /** 47 | * Installs a binding which will be specific to the constructed injector. 48 | * 49 | * @param binding the binding to install. 50 | * @param the type of values handled by the given binding. 51 | * @return this builder, for chaining. 52 | * @throws IllegalStateException if {@code build()} was already called on this builder. 53 | */ 54 | @NotNull 55 | @Contract("_ -> this") 56 | TargetedInjectorBuilder installBinding(@NotNull UninstalledBinding binding); 57 | 58 | /** 59 | * Builds the targeted injector instance from the bindings applied to this builder. The builder instance cannot be 60 | * reused after calling this method. 61 | * 62 | * @return the constructed injector using the bindings previously applied to this builder. 63 | * @throws IllegalStateException if {@code build()} was already called on this builder. 64 | */ 65 | @NotNull 66 | Injector build(); 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/util/NullMask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.util; 26 | 27 | import org.apiguardian.api.API; 28 | import org.jetbrains.annotations.NotNull; 29 | import org.jetbrains.annotations.Nullable; 30 | 31 | /** 32 | * Utility to mask and unmask null values. 33 | * 34 | * @author Pasqual K. 35 | * @since 2.0 36 | */ 37 | @API(status = API.Status.INTERNAL, since = "1.0") 38 | public final class NullMask { 39 | 40 | /** 41 | * A static object indicating that a value is null. 42 | */ 43 | private static final Object NULL = new Object(); 44 | 45 | private NullMask() { 46 | throw new UnsupportedOperationException(); 47 | } 48 | 49 | /** 50 | * Masks the given value with a null representing object if the given value is null. If the given value is present, 51 | * this method returns the given value. 52 | * 53 | * @param unmasked the value to mask if needed. 54 | * @return a masked value if the given value is null, the same value otherwise. 55 | */ 56 | public static @NotNull Object mask(@Nullable Object unmasked) { 57 | return unmasked != null ? unmasked : NULL; 58 | } 59 | 60 | /** 61 | * Unmasks the given object, returning null if the given object is masked. If the given object is not masked the given 62 | * value is returned. 63 | * 64 | * @param masked the value to unmask if needed. 65 | * @return null if the given value is masked, the same value otherwise. 66 | */ 67 | public static @Nullable Object unmask(@NotNull Object masked) { 68 | return masked == NULL ? null : masked; 69 | } 70 | 71 | /** 72 | * Checks if the given object was masked. 73 | * 74 | * @param candidate the candidate to check. 75 | * @return true if the given object is masked, false otherwise. 76 | */ 77 | public static boolean masked(@Nullable Object candidate) { 78 | return candidate == NULL; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/binding/annotation/BuilderAnnotationProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.binding.annotation; 26 | 27 | import dev.derklaro.aerogel.internal.util.PrimitiveUtil; 28 | import java.lang.annotation.Annotation; 29 | import java.lang.reflect.InvocationHandler; 30 | import java.lang.reflect.Method; 31 | import java.lang.reflect.Proxy; 32 | import org.jetbrains.annotations.NotNull; 33 | import org.jetbrains.annotations.Nullable; 34 | 35 | final class BuilderAnnotationProxy implements InvocationHandler { 36 | 37 | private A proxyInstance; 38 | private String lastAccessedProperty; 39 | 40 | private BuilderAnnotationProxy() { 41 | } 42 | 43 | @SuppressWarnings("unchecked") 44 | public static @NotNull BuilderAnnotationProxy make(@NotNull Class annotationType) { 45 | ClassLoader classLoader = annotationType.getClassLoader(); 46 | BuilderAnnotationProxy handler = new BuilderAnnotationProxy<>(); 47 | handler.proxyInstance = (A) Proxy.newProxyInstance(classLoader, new Class[]{annotationType}, handler); 48 | return handler; 49 | } 50 | 51 | @Override 52 | public @Nullable Object invoke( 53 | @NotNull Object proxy, 54 | @NotNull Method method, 55 | @NotNull Object[] args 56 | ) { 57 | this.lastAccessedProperty = method.getName(); 58 | 59 | // for primitives a default value must be returned, everything else can be null 60 | Class rt = method.getReturnType(); 61 | if (rt.isPrimitive()) { 62 | return PrimitiveUtil.defaultValue(rt); 63 | } else { 64 | return null; 65 | } 66 | } 67 | 68 | public @NotNull A proxyInstance() { 69 | return this.proxyInstance; 70 | } 71 | 72 | public @Nullable String getAndRemoveLastAccessedProperty() { 73 | String prop = this.lastAccessedProperty; 74 | this.lastAccessedProperty = null; 75 | return prop; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/ScopeApplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import dev.derklaro.aerogel.binding.key.BindingKey; 29 | import java.util.List; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.CheckReturnValue; 32 | import org.jetbrains.annotations.NotNull; 33 | 34 | /** 35 | * A scope that can be applied to a provider. A scope can be used to inject a state into a provider. Default bindings 36 | * are created without a scope, therefore instances created by providers are create-and-forget. Once the current 37 | * injection context ends, the constructed instance will no longer by known by the injector. A scope can be used to 38 | * define a longer lifetime for those instances. 39 | * 40 | * @author Pasqual Koschmieder 41 | * @since 3.0 42 | */ 43 | @FunctionalInterface 44 | @API(status = API.Status.STABLE, since = "3.0") 45 | public interface ScopeApplier { 46 | 47 | /** 48 | * Returns a new provider with this scope applied to it. If necessary, the method may obtain an instance from the 49 | * given provider. 50 | * 51 | * @param keys the keys of the binding that requests the scoping. 52 | * @param original the original provider to apply this scope to. 53 | * @param the type of value returned by the provider. 54 | * @return a new provider that scopes the given provider. 55 | */ 56 | @NotNull 57 | @CheckReturnValue 58 | ProviderWithContext applyScope( 59 | @NotNull List> keys, 60 | @NotNull ProviderWithContext original); 61 | 62 | /** 63 | * Marker interface to indicate that the scope applies some sort of singleton and that instances created during 64 | * construction should be unique. 65 | */ 66 | @FunctionalInterface 67 | @API(status = API.Status.STABLE, since = "3.0") 68 | interface Singleton extends ScopeApplier { 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/internal/factory/FactoryAutoEntryDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.internal.factory; 26 | 27 | import dev.derklaro.aerogel.auto.AutoEntryDecoder; 28 | import dev.derklaro.aerogel.auto.LazyBindingCollection; 29 | import dev.derklaro.aerogel.auto.annotation.Factory; 30 | import dev.derklaro.aerogel.auto.internal.util.AutoDecodingUtil; 31 | import dev.derklaro.aerogel.binding.key.BindingKey; 32 | import java.io.DataInput; 33 | import java.io.IOException; 34 | import java.lang.reflect.Method; 35 | import java.util.Arrays; 36 | import java.util.stream.Collectors; 37 | import org.jetbrains.annotations.NotNull; 38 | 39 | public final class FactoryAutoEntryDecoder implements AutoEntryDecoder { 40 | 41 | @Override 42 | public @NotNull String id() { 43 | return Factory.CODEC_ID; 44 | } 45 | 46 | @Override 47 | public @NotNull LazyBindingCollection decodeEntry( 48 | @NotNull DataInput dataInput, 49 | @NotNull ClassLoader loader 50 | ) throws IOException { 51 | String methodName = dataInput.readUTF(); 52 | Class declaring = AutoDecodingUtil.decodeType(dataInput, loader); 53 | Class[] methodArgTypes = AutoDecodingUtil.decodeTypes(dataInput, loader); 54 | 55 | try { 56 | Method factoryMethod = declaring.getDeclaredMethod(methodName, methodArgTypes); 57 | BindingKey methodBindingKey = BindingKey 58 | .of(factoryMethod.getGenericReturnType()) 59 | .selectQualifier(factoryMethod.getAnnotations()); 60 | return new FactoryLazyBindingCollection(methodBindingKey, factoryMethod); 61 | } catch (NoSuchMethodException exception) { 62 | String formattedArgs = Arrays.stream(methodArgTypes).map(Class::getName).collect(Collectors.joining(", ")); 63 | throw new IllegalStateException(String.format( 64 | "Factory method %s(%s) not found in %s", 65 | methodName, formattedArgs, declaring.getName())); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /auto/src/processing/java/dev/derklaro/aerogel/auto/processing/AutoEntryProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.processing; 26 | 27 | import java.io.DataOutput; 28 | import java.io.IOException; 29 | import java.lang.annotation.Annotation; 30 | import java.util.Collection; 31 | import javax.lang.model.element.Element; 32 | import org.apiguardian.api.API; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | /** 36 | * A processor for a specific auto annotation. When, during an annotation processing round, an element with the 37 | * supported annotation of this processor is found, this processor is invoked. It can, based on the given elements, emit 38 | * information into the provided data output which can be used for deserialization in runtime. 39 | * 40 | * @author Pasqual Koschmieder 41 | * @since 3.0 42 | */ 43 | @API(status = API.Status.STABLE, since = "3.0") 44 | public interface AutoEntryProcessor { 45 | 46 | /** 47 | * Get the annotation type that is handled by this auto entry processor. 48 | * 49 | * @return the annotation type that is handled by this auto entry processor. 50 | */ 51 | @NotNull 52 | Class handledAnnotation(); 53 | 54 | /** 55 | * Called if elements annotated with the handled annotations are found in a processing round. Based on the elements 56 | * the processor can write none, one or multiple entries into the given data output which will be available in runtime 57 | * for deserialization. 58 | * 59 | * @param output the output to write serialized data about the annotated elements into. 60 | * @param annotatedElements the elements that are annotated with the handled annotation. 61 | * @throws IOException if an I/O error occurs while serializing the information into the data output. 62 | */ 63 | void emitEntries( 64 | @NotNull DataOutput output, 65 | @NotNull Collection annotatedElements 66 | ) throws IOException; 67 | } 68 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | 74 | 75 | @rem Execute Gradle 76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 77 | 78 | :end 79 | @rem End local scope for the variables with windows NT shell 80 | if %ERRORLEVEL% equ 0 goto mainEnd 81 | 82 | :fail 83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 | rem the _cmd.exe /c_ return code! 85 | set EXIT_CODE=%ERRORLEVEL% 86 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 87 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 88 | exit /b %EXIT_CODE% 89 | 90 | :mainEnd 91 | if "%OS%"=="Windows_NT" endlocal 92 | 93 | :omega 94 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/annotation/AnnotationUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.annotation; 26 | 27 | import java.lang.annotation.Annotation; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | /** 34 | * Collection of utility methods to work with annotations. 35 | * 36 | * @author Pasqual Koschmieder 37 | * @since 3.0 38 | */ 39 | @API(status = API.Status.INTERNAL, since = "3.0") 40 | public final class AnnotationUtil { 41 | 42 | /** 43 | * Checks if the given annotation type has any properties (= any method declared). See JLS chapter 9.6.1 for method 44 | * declaration restrictions for annotations. 45 | * 46 | * @param annotationType the annotation type to check for properties. 47 | * @return true if the given annotation has properties, false otherwise. 48 | */ 49 | public static boolean hasProperties(@NotNull Class annotationType) { 50 | // no other checks needed, no other methods than property declarations are allowed 51 | // see JLS chapter 9: https://docs.oracle.com/javase/specs/jls/se21/html/jls-9.html#jls-9.6.1 52 | return annotationType.getDeclaredMethods().length > 0; 53 | } 54 | 55 | /** 56 | * Get the retention policy of the given annotation type. If the retention is not explicitly specified via @Retention 57 | * on the annotation type, the default CLASS retention is returned. 58 | * 59 | * @param annotationType the annotation type to get the retention policy of. 60 | * @return the retention policy of the given annotation. 61 | * @see Retention 62 | */ 63 | public static @NotNull RetentionPolicy extractRetention(@NotNull Class annotationType) { 64 | Retention retention = annotationType.getDeclaredAnnotation(Retention.class); 65 | return retention != null ? retention.value() : RetentionPolicy.CLASS; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /auto/src/main/java/dev/derklaro/aerogel/auto/internal/util/AutoDecodingUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.auto.internal.util; 26 | 27 | import java.io.DataInput; 28 | import java.io.IOException; 29 | import org.jetbrains.annotations.NotNull; 30 | import org.jetbrains.annotations.Nullable; 31 | 32 | public final class AutoDecodingUtil { 33 | 34 | private AutoDecodingUtil() { 35 | throw new UnsupportedOperationException(); 36 | } 37 | 38 | public static @NotNull Class[] decodeTypes( 39 | @NotNull DataInput dataInput, 40 | @Nullable ClassLoader loader 41 | ) throws IOException { 42 | int typeCount = dataInput.readInt(); 43 | Class[] types = new Class[typeCount]; 44 | for (int i = 0; i < typeCount; i++) { 45 | types[i] = decodeType(dataInput, loader); 46 | } 47 | 48 | return types; 49 | } 50 | 51 | public static @NotNull Class decodeType( 52 | @NotNull DataInput dataInput, 53 | @Nullable ClassLoader loader 54 | ) throws IOException { 55 | String className = dataInput.readUTF(); 56 | switch (className) { 57 | // primitive types (cannot be resolved via Class.forName) 58 | case "int": 59 | return int.class; 60 | case "byte": 61 | return byte.class; 62 | case "char": 63 | return char.class; 64 | case "long": 65 | return long.class; 66 | case "short": 67 | return short.class; 68 | case "float": 69 | return float.class; 70 | case "double": 71 | return double.class; 72 | case "boolean": 73 | return boolean.class; 74 | // reference type or primitive array, resolve via Class.forName 75 | // as it was already encoded into the correct format when writing 76 | default: 77 | try { 78 | return Class.forName(className, false, loader); 79 | } catch (ClassNotFoundException exception) { 80 | throw new IllegalStateException("Unable to locate class " + className + " using loader " + loader); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/util/BindingUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.util; 26 | 27 | import dev.derklaro.aerogel.binding.key.BindingKey; 28 | import jakarta.inject.Provider; 29 | import java.lang.reflect.ParameterizedType; 30 | import java.lang.reflect.Type; 31 | import org.jetbrains.annotations.NotNull; 32 | import org.jetbrains.annotations.Nullable; 33 | 34 | public final class BindingUtil { 35 | 36 | private BindingUtil() { 37 | throw new UnsupportedOperationException(); 38 | } 39 | 40 | /** 41 | * Checks if the given binding key is a provider. 42 | * 43 | * @param key the key to check. 44 | * @return true if the given binding key represents a provider, false otherwise. 45 | * @throws NullPointerException if the given key is null. 46 | */ 47 | public static boolean isProvider(@NotNull BindingKey key) { 48 | Type type = key.type(); 49 | if (type instanceof ParameterizedType) { 50 | ParameterizedType pt = (ParameterizedType) type; 51 | return pt.getRawType() == Provider.class; 52 | } 53 | 54 | return false; 55 | } 56 | 57 | /** 58 | * Extracts the component type of the provider represented by the given key. Returns null if the given key is not a 59 | * provider (which can be used to check if the key is a provider, but {@link #isProvider(BindingKey)} should be 60 | * preferred as this invocation causes an array copy). 61 | * 62 | * @param key the key to possibly extract the provider component type of. 63 | * @return the component type if the key represents a provider, null otherwise. 64 | * @throws NullPointerException if the given key is null. 65 | */ 66 | public static @Nullable Type extractProviderComponentType(@NotNull BindingKey key) { 67 | Type type = key.type(); 68 | if (type instanceof ParameterizedType) { 69 | ParameterizedType pt = (ParameterizedType) type; 70 | if (pt.getRawType() == Provider.class) { 71 | return pt.getActualTypeArguments()[0]; 72 | } 73 | } 74 | 75 | return null; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/provider/InstanceProviderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.provider; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import dev.derklaro.aerogel.internal.context.InjectionContext; 29 | import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; 30 | import org.jetbrains.annotations.NotNull; 31 | import org.jetbrains.annotations.Nullable; 32 | 33 | public final class InstanceProviderFactory implements ProviderFactory { 34 | 35 | private final T instance; 36 | 37 | private InstanceProviderFactory(@Nullable T instance) { 38 | this.instance = instance; 39 | } 40 | 41 | public static @NotNull InstanceProviderFactory ofInstance(@Nullable T instance) { 42 | return new InstanceProviderFactory<>(instance); 43 | } 44 | 45 | @Override 46 | public @NotNull ProviderWithContext constructProvider() { 47 | return new InstanceProvider<>(this.instance); 48 | } 49 | 50 | private static final class InstanceProvider implements ProviderWithContext { 51 | 52 | @SuppressWarnings("rawtypes") 53 | private static final AtomicReferenceFieldUpdater MEMBERS_INJECTED_UPDATER 54 | = AtomicReferenceFieldUpdater.newUpdater(InstanceProvider.class, Boolean.class, "membersInjected"); 55 | 56 | private final T instance; 57 | private volatile Boolean membersInjected; 58 | 59 | public InstanceProvider(@Nullable T instance) { 60 | this.instance = instance; 61 | this.membersInjected = Boolean.FALSE; 62 | } 63 | 64 | @Override 65 | public @Nullable T get(@NotNull InjectionContext context) { 66 | if (this.membersInjected) { 67 | return this.instance; 68 | } 69 | 70 | // prevent possible duplicate member injections due to concurrent calls to get() 71 | if (MEMBERS_INJECTED_UPDATER.compareAndSet(this, Boolean.FALSE, Boolean.TRUE)) { 72 | context.requestMemberInjectionSameBinding(this.instance); 73 | } 74 | 75 | return this.instance; 76 | } 77 | 78 | @Override 79 | public @NotNull String toString() { 80 | return "Fixed(" + this.instance + ")"; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/util/UnreflectionUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.util; 26 | 27 | import java.lang.invoke.MethodHandle; 28 | import java.lang.invoke.MethodHandles; 29 | import java.lang.reflect.AccessibleObject; 30 | import java.lang.reflect.Constructor; 31 | import java.lang.reflect.Field; 32 | import java.lang.reflect.Method; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | public final class UnreflectionUtil { 36 | 37 | private UnreflectionUtil() { 38 | throw new UnsupportedOperationException(); 39 | } 40 | 41 | public static @NotNull MethodHandle unreflectMethod( 42 | @NotNull Method method, 43 | @NotNull MethodHandles.Lookup baseLookup 44 | ) { 45 | return tryUnreflect(method, baseLookup::unreflect); 46 | } 47 | 48 | public static @NotNull MethodHandle unreflectFieldSetter( 49 | @NotNull Field field, 50 | @NotNull MethodHandles.Lookup baseLookup 51 | ) { 52 | return tryUnreflect(field, baseLookup::unreflectSetter); 53 | } 54 | 55 | public static @NotNull MethodHandle unreflectConstructor( 56 | @NotNull Constructor constructor, 57 | @NotNull MethodHandles.Lookup baseLookup 58 | ) { 59 | return tryUnreflect(constructor, baseLookup::unreflectConstructor); 60 | } 61 | 62 | private static @NotNull MethodHandle tryUnreflect( 63 | @NotNull A target, 64 | @NotNull Unreflector unreflector 65 | ) { 66 | try { 67 | // try normal unreflection 68 | return unreflector.unreflect(target); 69 | } catch (Exception ignored) { 70 | } 71 | 72 | try { 73 | // try forcing our way in 74 | target.setAccessible(true); 75 | return unreflector.unreflect(target); 76 | } catch (Exception exception) { 77 | throw new IllegalStateException( 78 | "Unable to access " + target + ". Provide a Lookup that has access during binding building"); 79 | } finally { 80 | target.setAccessible(false); 81 | } 82 | } 83 | 84 | @FunctionalInterface 85 | private interface Unreflector { 86 | 87 | @NotNull 88 | MethodHandle unreflect(@NotNull A target) throws Exception; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/MemberInjector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import org.apiguardian.api.API; 28 | import org.jetbrains.annotations.NotNull; 29 | import org.jetbrains.annotations.Nullable; 30 | 31 | /** 32 | * Injects methods and fields in classes that are marked as injectable. This process is usually executed after a class 33 | * instance was created by an injector, but can be manually executed by obtaining a member injector from an injector. 34 | * 35 | * @param the type to inject members in. 36 | * @author Pasqual Koschmieder 37 | * @since 1.0 38 | */ 39 | @API(status = API.Status.STABLE, since = "1.0") 40 | public interface MemberInjector { 41 | 42 | /** 43 | * Get the injector to which this member injector is bound. 44 | * 45 | * @return the injector to which this member injector is bound. 46 | */ 47 | @NotNull 48 | Injector injector(); 49 | 50 | /** 51 | * Get the target class of this member injector. This class was provided when the member injector from an injector. 52 | * 53 | * @return the target class of this member injector. 54 | */ 55 | @NotNull 56 | Class target(); 57 | 58 | /** 59 | * Injects the members of a class in the given instance. If the instance of a class is created by an injector, this 60 | * process is executed automatically. Therefore, if all class instances are created automatically, there is no need to 61 | * call this method manually. 62 | *

63 | * If the given instance is null, only static members will be injected in the target class, unless they were already 64 | * injected once by a different injector. 65 | *

66 | * Member injection follows these ordering rules: 67 | *

    68 | *
  1. supertype members are injected before subtype members. 69 | *
  2. static members are injected before instance members. 70 | *
  3. fields are injected before methods. 71 | *
  4. fields with the same modifier are sorted by name. 72 | *
  5. methods with the same modifier are sorted by {@link Order} or name for methods with the same ordering. 73 | *
74 | * 75 | * @param instance the instance to inject members in. 76 | */ 77 | void injectMembers(@Nullable T instance); 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/binding/InstalledBindingImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.binding; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.ScopeApplier; 29 | import dev.derklaro.aerogel.binding.BindingOptions; 30 | import dev.derklaro.aerogel.binding.InstalledBinding; 31 | import dev.derklaro.aerogel.binding.ProviderWithContext; 32 | import dev.derklaro.aerogel.binding.UninstalledBinding; 33 | import dev.derklaro.aerogel.binding.key.BindingKey; 34 | import java.util.List; 35 | import java.util.Optional; 36 | import org.jetbrains.annotations.NotNull; 37 | import org.jetbrains.annotations.Unmodifiable; 38 | 39 | final class InstalledBindingImpl implements InstalledBinding { 40 | 41 | private final Injector injector; 42 | private final UninstalledBinding source; 43 | 44 | private final ProviderWithContext providerWithContext; 45 | 46 | public InstalledBindingImpl( 47 | @NotNull Injector injector, 48 | @NotNull UninstalledBinding source, 49 | @NotNull ProviderWithContext providerWithContext 50 | ) { 51 | this.source = source; 52 | this.injector = injector; 53 | this.providerWithContext = providerWithContext; 54 | } 55 | 56 | @Override 57 | public @NotNull BindingKey mainKey() { 58 | return this.source.mainKey(); 59 | } 60 | 61 | @Override 62 | public @NotNull @Unmodifiable List> keys() { 63 | return this.source.keys(); 64 | } 65 | 66 | @Override 67 | public boolean supportsKey(@NotNull BindingKey key) { 68 | return this.source.supportsKey(key); 69 | } 70 | 71 | @Override 72 | public @NotNull Injector installedInjector() { 73 | return this.injector; 74 | } 75 | 76 | @Override 77 | public @NotNull BindingOptions options() { 78 | return this.source.options(); 79 | } 80 | 81 | @Override 82 | public @NotNull Optional scope() { 83 | return this.source.scope(); 84 | } 85 | 86 | @Override 87 | public @NotNull ProviderWithContext providerWithContext() { 88 | return this.providerWithContext; 89 | } 90 | 91 | @Override 92 | public @NotNull UninstalledBinding asUninstalled() { 93 | return this.source; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/InjectorBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import dev.derklaro.aerogel.binding.key.BindingKey; 28 | import java.lang.invoke.MethodHandles; 29 | import java.util.function.Predicate; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.Contract; 32 | import org.jetbrains.annotations.NotNull; 33 | 34 | /** 35 | * A builder for an injector which allows to fine-tune an injector instance. A new builder instance can be obtained by 36 | * using {@link Injector#builder()}. Using {@code Injector.builder().build()} would create an injector instance 37 | * identical to {@link Injector#newInjector()}. 38 | * 39 | * @author Pasqual Koschmieder 40 | * @since 3.0 41 | */ 42 | @API(status = API.Status.STABLE, since = "3.0") 43 | public interface InjectorBuilder { 44 | 45 | /** 46 | * Sets the member lookup that will be used to resolve reflective members of classes when needed (such as constructors 47 | * when resolving injection points and field/methods for member injection). If not explicitly set a default lookup 48 | * will be used instead. 49 | * 50 | * @param lookup the lookup instance to use for member lookups. 51 | * @return this builder, for chaining. 52 | */ 53 | @NotNull 54 | @Contract("_ -> this") 55 | InjectorBuilder memberLookup(@NotNull MethodHandles.Lookup lookup); 56 | 57 | /** 58 | * Sets the filter for jit bindings to use. By default, a jit binding can be created for all binding keys. The given 59 | * filter will be called for every key for which a jit binding would be necessary. If the filter indicates that no jit 60 | * binding should be created for a key an exception is thrown during the injection process. 61 | * 62 | * @param filter the filter to use for jit bindings. 63 | * @return this builder, for chaining. 64 | */ 65 | @NotNull 66 | @Contract("_ -> this") 67 | InjectorBuilder jitBindingFilter(@NotNull Predicate> filter); 68 | 69 | /** 70 | * Constructs a new injector instance based on the options provided to this builder. 71 | * 72 | * @return a new injector instance based on the options provided to this builder. 73 | */ 74 | @NotNull 75 | @Contract(value = " -> new", pure = true) 76 | Injector build(); 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/binding/DynamicBinding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.binding; 26 | 27 | import dev.derklaro.aerogel.binding.key.BindingKey; 28 | import java.util.Optional; 29 | import org.apiguardian.api.API; 30 | import org.jetbrains.annotations.NotNull; 31 | 32 | /** 33 | * A binding that can provide bindings for elements dynamically, for example based on annotation values. When a matching 34 | * request is made to a dynamic binding, the binding can decide if it can provide a binding for the requested element or 35 | * not. Return values are required to be predictable, therefore calling the {@link #tryMatch(BindingKey)} method with 36 | * the same binding key twice, should always return the same binding instance. Once a binding was resolved from a 37 | * dynamic binding, no subsequent dynamic bindings will be called, and the result will be stored as a fixed binding. 38 | * 39 | * @author Pasqual Koschmieder 40 | * @since 3.0 41 | */ 42 | @API(status = API.Status.STABLE, since = "3.0") 43 | public interface DynamicBinding { 44 | 45 | /** 46 | * Get if this dynamic binding would support creating a binding instance for the given binding key. If this method 47 | * returns {@code true} for the given binding key, a subsequent call to {@link #tryMatch(BindingKey)} with the same 48 | * key MUST return a binding. 49 | * 50 | * @param key the key to check for support. 51 | * @return true if this binding supports the given key, false otherwise. 52 | */ 53 | boolean supports(@NotNull BindingKey key); 54 | 55 | /** 56 | * Tries to match this binding against the given binding key. If this binding matches the given key and want to 57 | * provide a binding for it, the method should return an optional containing an uninstalled binding to use for the 58 | * element. In case this binding can't provide an instance for the key, the method should return an empty optional. 59 | * 60 | * @param key the binding key of the element that gets injected. 61 | * @param the type of value handled by the binding. 62 | * @return an uninstalled binding if this binding matches, an empty optional otherwise. 63 | */ 64 | @NotNull 65 | Optional> tryMatch(@NotNull BindingKey key); 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/context/scope/threadlocal/ThreadLocalInjectionContextScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.context.scope.threadlocal; 26 | 27 | import dev.derklaro.aerogel.internal.context.InjectionContext; 28 | import dev.derklaro.aerogel.internal.context.scope.InjectionContextScope; 29 | import java.util.function.Supplier; 30 | import org.apiguardian.api.API; 31 | import org.jetbrains.annotations.NotNull; 32 | import org.jetbrains.annotations.UnknownNullability; 33 | 34 | /** 35 | * An injection context scope that uses thread-locals to set the context of the current scope. 36 | * 37 | * @author Pasqual K. 38 | * @since 3.0 39 | */ 40 | @API(status = API.Status.INTERNAL, since = "3.0") 41 | final class ThreadLocalInjectionContextScope implements InjectionContextScope { 42 | 43 | private final InjectionContext context; 44 | private final ThreadLocal scopeThreadLocal; 45 | 46 | /** 47 | * Constructs a new thread local injection context scope. 48 | * 49 | * @param context the context that is wrapped in this scope. 50 | * @param scopeThreadLocal the thread local that is used by the context provider. 51 | */ 52 | public ThreadLocalInjectionContextScope( 53 | @NotNull InjectionContext context, 54 | @NotNull ThreadLocal scopeThreadLocal 55 | ) { 56 | this.context = context; 57 | this.scopeThreadLocal = scopeThreadLocal; 58 | } 59 | 60 | /** 61 | * {@inheritDoc} 62 | */ 63 | @Override 64 | public @NotNull InjectionContext context() { 65 | return this.context; 66 | } 67 | 68 | /** 69 | * {@inheritDoc} 70 | */ 71 | @Override 72 | public @UnknownNullability T executeScoped(@NotNull Supplier operation) { 73 | InjectionContextScope currentScope = this.scopeThreadLocal.get(); 74 | try { 75 | // update the thread local to use this scope, then call the given operation 76 | this.scopeThreadLocal.set(this); 77 | return operation.get(); 78 | } finally { 79 | // reset to the previous scope if present, else remove the mapping to the current scope 80 | if (currentScope != null) { 81 | this.scopeThreadLocal.set(currentScope); 82 | } else { 83 | this.scopeThreadLocal.remove(); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/util/MapUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.util; 26 | 27 | import java.util.Collections; 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | import java.util.concurrent.ConcurrentHashMap; 31 | import java.util.concurrent.ConcurrentMap; 32 | import java.util.function.Consumer; 33 | import org.apiguardian.api.API; 34 | import org.jetbrains.annotations.NotNull; 35 | import org.jetbrains.annotations.Unmodifiable; 36 | 37 | /** 38 | * A small utility to provide pre-configured map instances. 39 | * 40 | * @author Pasqual K. 41 | * @since 2.0 42 | */ 43 | @API(status = API.Status.INTERNAL, since = "1.0") 44 | public final class MapUtil { 45 | 46 | private MapUtil() { 47 | throw new UnsupportedOperationException(); 48 | } 49 | 50 | /** 51 | * Creates a new concurrent map instance with an initial capacity of 16, a load factor of 0.9 (to ensure dense 52 | * packaging which improves memory usage) and 1 shard (1 shard can handle multiple concurrent calls, there is no need 53 | * to create more shards). 54 | * 55 | * @param the type of keys which are stored in the map. 56 | * @param the type of values which are stored in the map. 57 | * @return a new concurrent map as described above. 58 | */ 59 | public static @NotNull ConcurrentMap newConcurrentMap() { 60 | return new ConcurrentHashMap<>(16, 0.9f, 1); 61 | } 62 | 63 | /** 64 | * Constructs a new map with the given expected size, which prevents resizing. The created map is passed to the given 65 | * decorator and then wrapped to be unmodifiable. 66 | * 67 | * @param elementCount the expected size of the map. 68 | * @param decorator the decorator to put the needed entries into the map before it's made unmodifiable. 69 | * @param the type of keys which are stored in the map. 70 | * @param the type of values which are stored in the map. 71 | * @return an unmodifiable map with the added entries from the given decorator. 72 | */ 73 | @Unmodifiable 74 | public static @NotNull Map staticMap(int elementCount, @NotNull Consumer> decorator) { 75 | Map map = new HashMap<>(elementCount, 1.0f); 76 | decorator.accept(map); 77 | return Collections.unmodifiableMap(map); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/dev/derklaro/aerogel/SecondCircularDependencyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel; 26 | 27 | import jakarta.inject.Inject; 28 | import org.junit.jupiter.api.Test; 29 | 30 | public class SecondCircularDependencyTest { 31 | 32 | @Test 33 | void test() { 34 | Injector injector = Injector.newInjector(); 35 | SomeService someService = injector.instance(SomeService.class); 36 | } 37 | 38 | @ProvidedBy(SomeProviderImpl.class) 39 | private interface SomeProvider { 40 | 41 | SomeService someService(); 42 | } 43 | 44 | @ProvidedBy(SomeOtherProviderImpl.class) 45 | private interface SomeOtherProvider { 46 | 47 | SomeProvider someProvider(); 48 | } 49 | 50 | private static final class SomeService { 51 | 52 | private final SomeProvider someProvider; 53 | private final SomeOtherService someOtherService; 54 | 55 | @Inject 56 | public SomeService(SomeProvider someProvider, SomeOtherService someOtherService) { 57 | this.someProvider = someProvider; 58 | this.someOtherService = someOtherService; 59 | } 60 | } 61 | 62 | private static final class SomeOtherService { 63 | 64 | private final SomeProvider someProvider; 65 | private final SomeOtherProvider someOtherProvider; 66 | 67 | @Inject 68 | public SomeOtherService(SomeProvider someProvider, SomeOtherProvider someOtherProvider) { 69 | this.someProvider = someProvider; 70 | this.someOtherProvider = someOtherProvider; 71 | } 72 | } 73 | 74 | private static final class SomeProviderImpl implements SomeProvider { 75 | 76 | private final SomeService someService; 77 | 78 | @Inject 79 | public SomeProviderImpl(SomeService someService) { 80 | this.someService = someService; 81 | } 82 | 83 | @Override 84 | public SomeService someService() { 85 | return this.someService; 86 | } 87 | } 88 | 89 | private static final class SomeOtherProviderImpl implements SomeOtherProvider { 90 | 91 | private final SomeProvider someProvider; 92 | 93 | @Inject 94 | public SomeOtherProviderImpl(SomeProvider someProvider) { 95 | this.someProvider = someProvider; 96 | } 97 | 98 | @Override 99 | public SomeProvider someProvider() { 100 | return this.someProvider; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/provider/ConstructingDelegatingProviderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.provider; 26 | 27 | import dev.derklaro.aerogel.binding.ProviderWithContext; 28 | import dev.derklaro.aerogel.internal.context.InjectionContext; 29 | import jakarta.inject.Provider; 30 | import java.lang.invoke.MethodHandles; 31 | import org.jetbrains.annotations.NotNull; 32 | import org.jetbrains.annotations.Nullable; 33 | 34 | public final class ConstructingDelegatingProviderFactory implements ProviderFactory { 35 | 36 | private final ProviderFactory> providerFactory; 37 | 38 | private ConstructingDelegatingProviderFactory(@NotNull ProviderFactory> providerFactory) { 39 | this.providerFactory = providerFactory; 40 | } 41 | 42 | public static @NotNull ConstructingDelegatingProviderFactory fromProviderClass( 43 | @NotNull Class> provider, 44 | @NotNull MethodHandles.Lookup lookup 45 | ) { 46 | ProviderFactory> providerFactory = ConstructorProviderFactory.fromClass(provider, lookup); 47 | return new ConstructingDelegatingProviderFactory<>(providerFactory); 48 | } 49 | 50 | @Override 51 | public @NotNull ProviderWithContext constructProvider() { 52 | ProviderWithContext> provider = this.providerFactory.constructProvider(); 53 | return new ConstructingDelegatingProvider<>(provider); 54 | } 55 | 56 | private static final class ConstructingDelegatingProvider implements ProviderWithContext { 57 | 58 | private final ProviderWithContext> providerConstructor; 59 | 60 | public ConstructingDelegatingProvider(@NotNull ProviderWithContext> providerConstructor) { 61 | this.providerConstructor = providerConstructor; 62 | } 63 | 64 | @Override 65 | public @Nullable T get(@NotNull InjectionContext context) { 66 | Provider provider = this.providerConstructor.get(context); 67 | if (provider == null) { 68 | throw new IllegalStateException("Provider " + this.providerConstructor + " illegally returned null value"); 69 | } 70 | 71 | return provider.get(); 72 | } 73 | 74 | @Override 75 | public @NotNull String toString() { 76 | return "ProviderClassDelegate(" + this.providerConstructor + ")"; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/injector/TargetedInjectorBuilderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.injector; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.TargetedInjectorBuilder; 29 | import dev.derklaro.aerogel.binding.InstalledBinding; 30 | import dev.derklaro.aerogel.binding.UninstalledBinding; 31 | import dev.derklaro.aerogel.binding.key.BindingKey; 32 | import dev.derklaro.aerogel.registry.Registry; 33 | import java.util.concurrent.atomic.AtomicReference; 34 | import org.jetbrains.annotations.NotNull; 35 | import org.jetbrains.annotations.Nullable; 36 | 37 | final class TargetedInjectorBuilderImpl implements TargetedInjectorBuilder { 38 | 39 | private final AtomicReference injectorRef; 40 | private final Registry.WithKeyMapping, InstalledBinding> bindingRegistry; 41 | 42 | /* trusted */ 43 | TargetedInjectorBuilderImpl( 44 | @NotNull Injector parent, 45 | @NotNull Injector nonTargetedInjector, 46 | @NotNull InjectorOptions injectorOptions 47 | ) { 48 | this.bindingRegistry = parent.bindingRegistry().createChildRegistry(); 49 | 50 | TargetedInjectorImpl injector = new TargetedInjectorImpl( 51 | parent, 52 | nonTargetedInjector, 53 | injectorOptions, 54 | this.bindingRegistry); 55 | this.injectorRef = new AtomicReference<>(injector); 56 | } 57 | 58 | private static @NotNull TargetedInjectorImpl validateInjectorPresence(@Nullable TargetedInjectorImpl maybeInjector) { 59 | if (maybeInjector == null) { 60 | throw new IllegalStateException("specific injector builder already targeted"); 61 | } 62 | return maybeInjector; 63 | } 64 | 65 | @Override 66 | public @NotNull TargetedInjectorBuilder installBinding(@NotNull UninstalledBinding binding) { 67 | TargetedInjectorImpl refInjector = this.injectorRef.get(); 68 | TargetedInjectorImpl injector = validateInjectorPresence(refInjector); 69 | 70 | InstalledBinding installedBinding = binding.prepareForInstallation(injector); 71 | for (BindingKey key : binding.keys()) { 72 | this.bindingRegistry.register(key, installedBinding); 73 | } 74 | 75 | return this; 76 | } 77 | 78 | @Override 79 | public @NotNull Injector build() { 80 | TargetedInjectorImpl refInjector = this.injectorRef.getAndSet(null); 81 | return validateInjectorPresence(refInjector); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/dev/derklaro/aerogel/internal/member/DefaultMemberInjector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of aerogel, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2021-2025 Pasqual K. and contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package dev.derklaro.aerogel.internal.member; 26 | 27 | import dev.derklaro.aerogel.Injector; 28 | import dev.derklaro.aerogel.MemberInjector; 29 | import java.lang.invoke.MethodHandles; 30 | import java.util.ArrayList; 31 | import java.util.Collection; 32 | import java.util.List; 33 | import org.apiguardian.api.API; 34 | import org.jetbrains.annotations.NotNull; 35 | import org.jetbrains.annotations.Nullable; 36 | 37 | /** 38 | * A default implementation of a {@link MemberInjector}. 39 | * 40 | * @author Pasqual K. 41 | * @since 1.0 42 | */ 43 | @API(status = API.Status.INTERNAL, since = "1.0") 44 | public final class DefaultMemberInjector implements MemberInjector { 45 | 46 | private final Injector injector; 47 | private final Class targetClass; 48 | 49 | private final List memberInjectionExecutors; 50 | 51 | public DefaultMemberInjector( 52 | @NotNull Class targetClass, 53 | @NotNull Injector injector, 54 | @NotNull MethodHandles.Lookup lookup 55 | ) { 56 | this.injector = injector; 57 | this.targetClass = targetClass; 58 | 59 | Collection injectableMembers = InjectionMemberCache.computeMemberTree(targetClass); 60 | this.memberInjectionExecutors = new ArrayList<>(injectableMembers.size()); 61 | for (InjectableMember injectableMember : injectableMembers) { 62 | try { 63 | MemberInjectionExecutor executor = injectableMember.provideInjectionExecutor(injector, lookup); 64 | this.memberInjectionExecutors.add(executor); 65 | } catch (Exception ignored) { 66 | // exceptions are used here to indicate that injection the particular member is not supported, just ignore that 67 | } 68 | } 69 | } 70 | 71 | @Override 72 | public @NotNull Injector injector() { 73 | return this.injector; 74 | } 75 | 76 | @Override 77 | public @NotNull Class target() { 78 | return this.targetClass; 79 | } 80 | 81 | @Override 82 | public void injectMembers(@Nullable T instance) { 83 | try { 84 | for (MemberInjectionExecutor memberInjectionExecutor : this.memberInjectionExecutors) { 85 | memberInjectionExecutor.executeInjection(instance); 86 | } 87 | } catch (Throwable throwable) { 88 | throw new IllegalStateException("Issue while injecting members in " + this.targetClass, throwable); 89 | } 90 | } 91 | } 92 | --------------------------------------------------------------------------------