├── .all-contributorsrc ├── .github ├── CODEOWNERS ├── dependabot.yml ├── project.yml └── workflows │ ├── build.yml │ ├── pre-release.yml │ ├── quarkus-snapshot.yaml │ ├── release-perform.yml │ └── release-prepare.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── mybatis-plus ├── deployment │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── quarkiverse │ │ └── mybatis │ │ └── plus │ │ └── deployment │ │ └── MyBatisPlusProcessor.java ├── docs │ ├── antora.yml │ ├── modules │ │ └── ROOT │ │ │ ├── nav.adoc │ │ │ └── pages │ │ │ ├── includes │ │ │ ├── attributes.adoc │ │ │ └── quarkus-mybatis-plus.adoc │ │ │ └── index.adoc │ ├── pom.xml │ └── templates │ │ └── includes │ │ └── attributes.adoc ├── integration-tests │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── quarkiverse │ │ │ │ └── it │ │ │ │ └── mybatis │ │ │ │ └── plus │ │ │ │ ├── CustomBaseMapper.java │ │ │ │ ├── EasySqlInjector.java │ │ │ │ ├── MyBatisPlusResource.java │ │ │ │ ├── MyObjectHandler.java │ │ │ │ ├── MybatisPlusServiceResource.java │ │ │ │ ├── User.java │ │ │ │ ├── UserMapper.java │ │ │ │ ├── UserServiceImpl.java │ │ │ │ └── UuidTypeHandler.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── insert.sql │ │ └── test │ │ └── java │ │ └── io │ │ └── quarkiverse │ │ └── it │ │ └── mybatis │ │ └── plus │ │ ├── MyBatisPlusIT.java │ │ ├── MyBatisPlusTest.java │ │ ├── MybatisPlusServiceTest.java │ │ └── TestResources.java ├── pom.xml └── runtime │ ├── pom.xml │ └── src │ └── main │ ├── java │ ├── com │ │ └── baomidou │ │ │ └── mybatisplus │ │ │ └── core │ │ │ ├── metadata │ │ │ └── MapperProxyMetadata.java │ │ │ └── toolkit │ │ │ └── reflect │ │ │ └── SpringReflectionHelper.java │ └── io │ │ └── quarkiverse │ │ └── mybatis │ │ └── plus │ │ ├── MyBatisPlusConfig.java │ │ ├── QuarkusCompatibleSet.java │ │ ├── extension │ │ ├── repository │ │ │ └── CrudRepository.java │ │ └── service │ │ │ ├── IService.java │ │ │ └── impl │ │ │ └── ServiceImpl.java │ │ └── runtime │ │ ├── GenericTypeResolverImpl.java │ │ ├── MyBatisPlusConfigurationFactory.java │ │ ├── MyBatisPlusRecorder.java │ │ └── MyBatisPlusXMLConfigDelegateBuilder.java │ └── resources │ └── META-INF │ ├── quarkus-extension.yaml │ └── services │ └── com.baomidou.mybatisplus.core.spi.CompatibleSet ├── mybatis ├── README.md ├── deployment │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── quarkiverse │ │ │ └── mybatis │ │ │ └── deployment │ │ │ ├── ConfigurationCustomizerBuildItem.java │ │ │ ├── ConfigurationFactoryBuildItem.java │ │ │ ├── MyBatisMappedJdbcTypeBuildItem.java │ │ │ ├── MyBatisMappedTypeBuildItem.java │ │ │ ├── MyBatisMapperBuildItem.java │ │ │ ├── MyBatisProcessor.java │ │ │ ├── MyBatisXmlConfigBuildItem.java │ │ │ ├── SqlSessionFactoryBuildItem.java │ │ │ ├── SqlSessionFactoryBuilderBuildItem.java │ │ │ ├── SqlSessionManagerBuildItem.java │ │ │ └── XMLConfigBuilderBuildItem.java │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── quarkiverse │ │ │ └── mybatis │ │ │ └── test │ │ │ ├── MyBatisTest.java │ │ │ ├── TestResources.java │ │ │ ├── User.java │ │ │ ├── UserMapper.java │ │ │ ├── UuidJdbcTypeHandler.java │ │ │ └── UuidTypeHandler.java │ │ └── resources │ │ ├── application.properties │ │ └── insert.sql ├── docs │ ├── antora.yml │ ├── modules │ │ └── ROOT │ │ │ ├── nav.adoc │ │ │ └── pages │ │ │ ├── includes │ │ │ ├── attributes.adoc │ │ │ └── quarkus-mybatis.adoc │ │ │ └── index.adoc │ ├── pom.xml │ └── templates │ │ └── includes │ │ └── attributes.adoc ├── integration-tests │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── quarkiverse │ │ │ │ └── it │ │ │ │ └── mybatis │ │ │ │ ├── Book.java │ │ │ │ ├── BookMapper.java │ │ │ │ ├── DerbyUserMapper.java │ │ │ │ ├── MyBatisResource.java │ │ │ │ ├── PageConfigurationFactory.java │ │ │ │ ├── SqlProviderAdapter.java │ │ │ │ ├── User.java │ │ │ │ ├── UserMapper.java │ │ │ │ ├── UuidJdbcTypeHandler.java │ │ │ │ └── UuidTypeHandler.java │ │ └── resources │ │ │ ├── application-xml.properties │ │ │ ├── application.properties │ │ │ ├── insert-derby.sql │ │ │ ├── insert.sql │ │ │ ├── mapper │ │ │ ├── DerbyUserMapper.xml │ │ │ └── UserMapper.xml │ │ │ ├── mybatis-config.xml │ │ │ └── otherMapper │ │ │ └── BookMapper.xml │ │ └── test │ │ └── java │ │ └── io │ │ └── quarkiverse │ │ └── it │ │ └── mybatis │ │ ├── BaseMyBatisTestCase.java │ │ ├── MultipleDataSourcesTest.java │ │ ├── MyBatisIT.java │ │ ├── MyBatisTest.java │ │ ├── MyBatisXmlConfigIT.java │ │ ├── MyBatisXmlConfigTest.java │ │ ├── TestResources.java │ │ └── XmlConfigProfile.java ├── pom.xml └── runtime │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── io │ │ └── quarkiverse │ │ └── mybatis │ │ └── runtime │ │ ├── ConfigurationFactory.java │ │ ├── MyBatisConfigurationFactory.java │ │ ├── MyBatisRecorder.java │ │ ├── MyBatisXMLConfigDelegateBuilder.java │ │ ├── QuarkusDataSourceFactory.java │ │ ├── QuarkusDatabaseIdProvider.java │ │ ├── TransactionalSqlSession.java │ │ ├── XMLConfigDelegateBuilder.java │ │ ├── config │ │ ├── MyBatisDataSourceRuntimeConfig.java │ │ └── MyBatisRuntimeConfig.java │ │ └── meta │ │ └── MapperDataSource.java │ └── resources │ └── META-INF │ └── quarkus-extension.yaml └── pom.xml /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "zhfeng", 10 | "name": "Amos Feng", 11 | "avatar_url": "https://avatars2.githubusercontent.com/u/1246139?v=4", 12 | "profile": "https://github.com/zhfeng", 13 | "contributions": [ 14 | "code", 15 | "maintenance" 16 | ] 17 | }, 18 | { 19 | "login": "362228416", 20 | "name": "Chao", 21 | "avatar_url": "https://avatars.githubusercontent.com/u/5248797?v=4", 22 | "profile": "https://github.com/362228416", 23 | "contributions": [ 24 | "code" 25 | ] 26 | }, 27 | { 28 | "login": "AndLvovSky", 29 | "name": "Viktor Ilvovskyi", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/46902956?v=4", 31 | "profile": "https://github.com/AndLvovSky", 32 | "contributions": [ 33 | "code" 34 | ] 35 | }, 36 | { 37 | "login": "igor-dmitriev", 38 | "name": "Igor Dmitriev", 39 | "avatar_url": "https://avatars.githubusercontent.com/u/4592740?v=4", 40 | "profile": "https://github.com/igor-dmitriev", 41 | "contributions": [ 42 | "code" 43 | ] 44 | }, 45 | { 46 | "login": "kbrumer", 47 | "name": "Ken Brumer", 48 | "avatar_url": "https://avatars.githubusercontent.com/u/244873?v=4", 49 | "profile": "https://github.com/kbrumer", 50 | "contributions": [ 51 | "code" 52 | ] 53 | }, 54 | { 55 | "login": "zohar-soul", 56 | "name": "Zohar", 57 | "avatar_url": "https://avatars.githubusercontent.com/u/13990539?v=4", 58 | "profile": "https://github.com/zohar-soul", 59 | "contributions": [ 60 | "maintenance" 61 | ] 62 | }, 63 | { 64 | "login": "y-bowen", 65 | "name": "bowen", 66 | "avatar_url": "https://avatars.githubusercontent.com/u/20274912?v=4", 67 | "profile": "https://github.com/y-bowen", 68 | "contributions": [ 69 | "code" 70 | ] 71 | }, 72 | { 73 | "login": "kwseeker", 74 | "name": "Arvin Lee", 75 | "avatar_url": "https://avatars.githubusercontent.com/u/7456558?v=4", 76 | "profile": "https://github.com/kwseeker", 77 | "contributions": [ 78 | "code" 79 | ] 80 | }, 81 | { 82 | "login": "renemarkvard-sosint", 83 | "name": "renemarkvard-sosint", 84 | "avatar_url": "https://avatars.githubusercontent.com/u/194897321?v=4", 85 | "profile": "https://github.com/renemarkvard-sosint", 86 | "contributions": [ 87 | "code" 88 | ] 89 | }, 90 | { 91 | "login": "Fengxq2014", 92 | "name": "DefNed", 93 | "avatar_url": "https://avatars.githubusercontent.com/u/8519834?v=4", 94 | "profile": "https://blog.dfned.com/", 95 | "contributions": [ 96 | "code" 97 | ] 98 | } 99 | ], 100 | "contributorsPerLine": 7, 101 | "projectName": "quarkus-mybatis", 102 | "projectOwner": "quarkiverse", 103 | "repoType": "github", 104 | "repoHost": "https://github.com", 105 | "skipCi": true, 106 | "commitType": "docs", 107 | "commitConvention": "angular" 108 | } 109 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 5 | 6 | # The '*' pattern is global owners. 7 | 8 | # Order is important. The last matching pattern has the most precedence. 9 | # The folders are ordered as follows: 10 | 11 | # In each subsection folders are ordered first by depth, then alphabetically. 12 | # This should make it easy to add new rules without breaking existing ones. 13 | 14 | * @quarkiverse/quarkiverse-mybatis 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | - package-ecosystem: "maven" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | ignore: 17 | - dependency-name: "org.apache.maven.plugins:maven-compiler-plugin" 18 | - dependency-name: "org.springframework:spring-aop" 19 | - package-ecosystem: "maven" 20 | directory: "/" 21 | schedule: 22 | interval: "daily" 23 | target-branch: "1.x" 24 | ignore: 25 | - dependency-name: "org.apache.maven.plugins:maven-compiler-plugin" 26 | - dependency-name: "org.springframework:spring-aop" 27 | - dependency-name: "io.quarkus:*" 28 | versions: "[3.0,)" 29 | -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse MyBatis Extension 2 | release: 3 | current-version: 2.4.0 4 | next-version: 999-SNAPSHOT 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - "master" 7 | - "1.x" 8 | paths-ignore: 9 | - '.gitignore' 10 | - 'CODEOWNERS' 11 | - 'LICENSE' 12 | - 'README*' 13 | pull_request: 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - name: Set up JDK 17 24 | uses: actions/setup-java@v4 25 | with: 26 | distribution: temurin 27 | java-version: 17 28 | 29 | - name: Cache local Maven repository 30 | uses: actions/cache@v4 31 | with: 32 | path: ~/.m2/repository 33 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 34 | restore-keys: | 35 | ${{ runner.os }}-maven- 36 | 37 | - name: Build with Maven 38 | run: mvn -B formatter:validate verify --file pom.xml 39 | 40 | - name: Run Native Check (if maven build success) 41 | if: success() 42 | run: mvn -Dnative -Dquarkus.native.container-build=true -B verify --file pom.xml 43 | 44 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Pre Release 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/project.yml' 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | pre-release: 14 | name: Pre-Release 15 | uses: quarkiverse/.github/.github/workflows/pre-release.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/quarkus-snapshot.yaml: -------------------------------------------------------------------------------- 1 | name: "Quarkus ecosystem CI" 2 | on: 3 | watch: 4 | types: [started] 5 | 6 | # For this CI to work, ECOSYSTEM_CI_TOKEN needs to contain a GitHub with rights to close the Quarkus issue that the user/bot has opened, 7 | # while 'ECOSYSTEM_CI_REPO_PATH' needs to be set to the corresponding path in the 'quarkusio/quarkus-ecosystem-ci' repository 8 | 9 | env: 10 | ECOSYSTEM_CI_REPO: quarkusio/quarkus-ecosystem-ci 11 | ECOSYSTEM_CI_REPO_FILE: context.yaml 12 | JAVA_VERSION: 17 13 | 14 | ######################### 15 | # Repo specific setting # 16 | ######################### 17 | 18 | ECOSYSTEM_CI_REPO_PATH: quarkiverse-mybatis 19 | 20 | jobs: 21 | build: 22 | name: "Build against latest Quarkus snapshot" 23 | runs-on: ubuntu-latest 24 | if: github.actor == 'quarkusbot' || github.actor == 'quarkiversebot' 25 | 26 | steps: 27 | - name: Set up Java 28 | uses: actions/setup-java@v4 29 | with: 30 | distribution: temurin 31 | java-version: ${{ env.JAVA_VERSION }} 32 | 33 | - name: Checkout repo 34 | uses: actions/checkout@v4 35 | with: 36 | path: current-repo 37 | 38 | - name: Checkout Ecosystem 39 | uses: actions/checkout@v4 40 | with: 41 | repository: ${{ env.ECOSYSTEM_CI_REPO }} 42 | path: ecosystem-ci 43 | 44 | - name: Setup and Run Tests 45 | run: ./ecosystem-ci/setup-and-test 46 | env: 47 | ECOSYSTEM_CI_TOKEN: ${{ secrets.ECOSYSTEM_CI_TOKEN }} 48 | -------------------------------------------------------------------------------- /.github/workflows/release-perform.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Perform Release 2 | run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: 'Tag to release' 11 | required: true 12 | 13 | permissions: 14 | attestations: write 15 | id-token: write 16 | contents: read 17 | 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | perform-release: 24 | name: Perform Release 25 | uses: quarkiverse/.github/.github/workflows/perform-release.yml@main 26 | secrets: inherit 27 | with: 28 | version: ${{github.event.inputs.tag || github.ref_name}} 29 | -------------------------------------------------------------------------------- /.github/workflows/release-prepare.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Prepare Release 2 | 3 | on: 4 | pull_request: 5 | types: [ closed ] 6 | paths: 7 | - '.github/project.yml' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | prepare-release: 15 | name: Prepare Release 16 | if: ${{ github.event.pull_request.merged == true}} 17 | uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Eclipse 26 | .project 27 | .classpath 28 | .settings/ 29 | bin/ 30 | 31 | # IntelliJ 32 | .idea 33 | *.ipr 34 | *.iml 35 | *.iws 36 | 37 | # NetBeans 38 | nb-configuration.xml 39 | 40 | # Visual Studio Code 41 | .vscode 42 | .factorypath 43 | 44 | # OSX 45 | .DS_Store 46 | 47 | # Vim 48 | *.swp 49 | *.swo 50 | 51 | # patch 52 | *.orig 53 | *.rej 54 | 55 | # Gradle 56 | .gradle/ 57 | build/ 58 | 59 | # Maven 60 | target/ 61 | pom.xml.tag 62 | pom.xml.releaseBackup 63 | pom.xml.versionsBackup 64 | release.properties 65 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quarkus MyBatis Extension 2 | [![Build](https://github.com/quarkiverse/quarkus-mybatis/workflows/Build/badge.svg?branch=master)](https://github.com/quarkiverse/quarkus-mybatis/actions?query=workflow%3ABuild) 3 | [![License](https://img.shields.io/github/license/quarkiverse/quarkus-mybatis)](http://www.apache.org/licenses/LICENSE-2.0) 4 | [![Central](https://img.shields.io/maven-central/v/io.quarkiverse.mybatis/quarkus-mybatis-parent?color=green)](https://search.maven.org/search?q=g:io.quarkiverse.mybatis%20AND%20a:quarkus-mybatis-parent) 5 | 6 | [![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors-) 7 | 8 | 9 | MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. This extension provides the developers ease of configuration and native support. Add the following dependency in your pom.xml to get started, 10 | 11 | ```xml 12 | 13 | io.quarkiverse.mybatis 14 | quarkus-mybatis 15 | 16 | ``` 17 | 18 | And then your can use the ```@Mapper``` in your application just like 19 | 20 | ```java 21 | @Mapper 22 | public interface UserMapper { 23 | 24 | @Select("SELECT * FROM USERS WHERE id = #{id}") 25 | User getUser(Integer id); 26 | 27 | @Insert("INSERT INTO USERS (id, name) VALUES (#{id}, #{name})") 28 | Integer createUser(@Param("id") Integer id, @Param("name") String name); 29 | 30 | @Delete("DELETE FROM USERS WHERE id = #{id}") 31 | Integer removeUser(Integer id); 32 | } 33 | ``` 34 | 35 | For more information and quickstart, you can check the complete [documentation](https://quarkiverse.github.io/quarkiverse-docs/quarkus-mybatis/dev/index.html). 36 | 37 | ## Contributors ✨ 38 | 39 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
Amos Feng
Amos Feng

💻 🚧
Chao
Chao

💻
Viktor Ilvovskyi
Viktor Ilvovskyi

💻
Igor Dmitriev
Igor Dmitriev

💻
Ken Brumer
Ken Brumer

💻
Zohar
Zohar

🚧
bowen
bowen

💻
Arvin Lee
Arvin Lee

💻
renemarkvard-sosint
renemarkvard-sosint

💻
DefNed
DefNed

💻
62 | 63 | 64 | 65 | 66 | 67 | 68 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 69 | -------------------------------------------------------------------------------- /mybatis-plus/deployment/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.quarkiverse.mybatis 5 | quarkus-mybatis-plus-parent 6 | 999-SNAPSHOT 7 | ../ 8 | 9 | 4.0.0 10 | 11 | quarkus-mybatis-plus-deployment 12 | Quarkus - Mybatis Plus - Deployment 13 | 14 | 15 | 16 | io.quarkiverse.mybatis 17 | quarkus-mybatis-deployment 18 | ${project.version} 19 | 20 | 21 | io.quarkiverse.mybatis 22 | quarkus-mybatis-plus 23 | ${project.version} 24 | 25 | 26 | 27 | io.quarkus 28 | quarkus-junit5-internal 29 | test 30 | 31 | 32 | io.quarkus 33 | quarkus-test-h2 34 | test 35 | 36 | 37 | io.quarkus 38 | quarkus-test-derby 39 | test 40 | 41 | 42 | io.quarkus 43 | quarkus-jdbc-h2-deployment 44 | test 45 | 46 | 47 | io.quarkus 48 | quarkus-jdbc-derby 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | maven-compiler-plugin 57 | 58 | 59 | 60 | io.quarkus 61 | quarkus-extension-processor 62 | ${quarkus.version} 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /mybatis-plus/deployment/src/main/java/io/quarkiverse/mybatis/plus/deployment/MyBatisPlusProcessor.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.deployment; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.executor.Executor; 6 | import org.apache.ibatis.executor.statement.StatementHandler; 7 | import org.apache.ibatis.mapping.BoundSql; 8 | import org.jboss.jandex.AnnotationInstance; 9 | import org.jboss.jandex.AnnotationTarget; 10 | import org.jboss.jandex.ClassInfo; 11 | import org.jboss.jandex.DotName; 12 | import org.jboss.logging.Logger; 13 | 14 | import com.baomidou.mybatisplus.annotation.TableName; 15 | import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder; 16 | import com.baomidou.mybatisplus.core.conditions.Wrapper; 17 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 18 | 19 | import io.quarkiverse.mybatis.deployment.ConfigurationCustomizerBuildItem; 20 | import io.quarkiverse.mybatis.deployment.ConfigurationFactoryBuildItem; 21 | import io.quarkiverse.mybatis.deployment.SqlSessionFactoryBuildItem; 22 | import io.quarkiverse.mybatis.deployment.SqlSessionFactoryBuilderBuildItem; 23 | import io.quarkiverse.mybatis.deployment.XMLConfigBuilderBuildItem; 24 | import io.quarkiverse.mybatis.plus.MyBatisPlusConfig; 25 | import io.quarkiverse.mybatis.plus.runtime.MyBatisPlusConfigurationFactory; 26 | import io.quarkiverse.mybatis.plus.runtime.MyBatisPlusRecorder; 27 | import io.quarkiverse.mybatis.plus.runtime.MyBatisPlusXMLConfigDelegateBuilder; 28 | import io.quarkiverse.mybatis.runtime.meta.MapperDataSource; 29 | import io.quarkus.deployment.annotations.BuildProducer; 30 | import io.quarkus.deployment.annotations.BuildStep; 31 | import io.quarkus.deployment.annotations.ExecutionTime; 32 | import io.quarkus.deployment.annotations.Record; 33 | import io.quarkus.deployment.builditem.CombinedIndexBuildItem; 34 | import io.quarkus.deployment.builditem.FeatureBuildItem; 35 | import io.quarkus.deployment.builditem.IndexDependencyBuildItem; 36 | import io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBuildItem; 37 | import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; 38 | 39 | public class MyBatisPlusProcessor { 40 | 41 | private static final String FEATURE = "mybatis-plus"; 42 | private static final DotName MYBATIS_PLUS_MAPPER = DotName.createSimple(BaseMapper.class.getName()); 43 | private static final DotName MYBATIS_MAPPER_DATA_SOURCE = DotName.createSimple(MapperDataSource.class.getName()); 44 | private static final DotName MYBATIS_PLUS_WRAPPER = DotName.createSimple(Wrapper.class.getName()); 45 | private static final Logger LOG = Logger.getLogger(MyBatisPlusProcessor.class); 46 | 47 | @BuildStep 48 | FeatureBuildItem feature() { 49 | return new FeatureBuildItem(FEATURE); 50 | } 51 | 52 | @BuildStep 53 | ConfigurationFactoryBuildItem createConfigurationFactory() { 54 | return new ConfigurationFactoryBuildItem(new MyBatisPlusConfigurationFactory()); 55 | } 56 | 57 | @BuildStep 58 | SqlSessionFactoryBuilderBuildItem createSqlSessionFactoryBuilder() { 59 | return new SqlSessionFactoryBuilderBuildItem(new MybatisSqlSessionFactoryBuilder()); 60 | } 61 | 62 | @BuildStep 63 | XMLConfigBuilderBuildItem createXMLConfigBuilder() throws Exception { 64 | return new XMLConfigBuilderBuildItem(new MyBatisPlusXMLConfigDelegateBuilder()); 65 | } 66 | 67 | @BuildStep 68 | void addDependencies(BuildProducer indexDependency) { 69 | indexDependency.produce(new IndexDependencyBuildItem("com.baomidou", "mybatis-plus-core")); 70 | } 71 | 72 | @BuildStep 73 | void reflectiveClasses(BuildProducer reflectiveClass, 74 | BuildProducer proxyClass, 75 | CombinedIndexBuildItem indexBuildItem) { 76 | reflectiveClass.produce(ReflectiveClassBuildItem.builder(StatementHandler.class, 77 | Executor.class).methods(true).fields(false).build()); 78 | reflectiveClass.produce(ReflectiveClassBuildItem.builder(BoundSql.class).methods(true).fields(true).build()); 79 | proxyClass.produce(new NativeImageProxyDefinitionBuildItem(StatementHandler.class.getName())); 80 | proxyClass.produce(new NativeImageProxyDefinitionBuildItem(Executor.class.getName())); 81 | 82 | for (AnnotationInstance i : indexBuildItem.getIndex().getAnnotations(DotName.createSimple(TableName.class.getName()))) { 83 | if (i.target().kind() == AnnotationTarget.Kind.CLASS) { 84 | DotName dotName = i.target().asClass().name(); 85 | reflectiveClass 86 | .produce(ReflectiveClassBuildItem.builder(dotName.toString()).methods(true).fields(false).build()); 87 | } 88 | } 89 | reflectiveClass 90 | .produce(ReflectiveClassBuildItem.builder(MYBATIS_PLUS_WRAPPER.toString()).methods(true).fields(true).build()); 91 | for (ClassInfo classInfo : indexBuildItem.getIndex().getAllKnownSubclasses(MYBATIS_PLUS_WRAPPER)) { 92 | reflectiveClass 93 | .produce(ReflectiveClassBuildItem.builder(classInfo.name().toString()).methods(true).fields(true).build()); 94 | } 95 | } 96 | 97 | @BuildStep 98 | @Record(ExecutionTime.STATIC_INIT) 99 | void init(List sqlSessionFactoryBuildItems, 100 | MyBatisPlusConfig config, 101 | MyBatisPlusRecorder recorder) { 102 | sqlSessionFactoryBuildItems 103 | .forEach(sqlSessionFactory -> recorder.initSqlSession(sqlSessionFactory.getSqlSessionFactory(), config)); 104 | } 105 | 106 | @BuildStep 107 | @Record(ExecutionTime.STATIC_INIT) 108 | ConfigurationCustomizerBuildItem addCustomSqlInjector(MyBatisPlusRecorder recorder, MyBatisPlusConfig config) { 109 | return new ConfigurationCustomizerBuildItem(recorder.addCustomSqlInjector(config)); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /mybatis-plus/docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: quarkus-mybatis-plus 2 | title: Quarkus MyBatis Plus 3 | version: dev 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | -------------------------------------------------------------------------------- /mybatis-plus/docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Introduction] 2 | -------------------------------------------------------------------------------- /mybatis-plus/docs/modules/ROOT/pages/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :quarkus-version: 3.18.2 2 | :quarkus-mybatis-plus-version: 2.2.4 3 | 4 | :mybatis-root-url: https://mybatis.org/mybatis-3/ 5 | :mybatis-plus-root-url: https://mybatis.plus/ 6 | -------------------------------------------------------------------------------- /mybatis-plus/docs/modules/ROOT/pages/includes/quarkus-mybatis-plus.adoc: -------------------------------------------------------------------------------- 1 | 2 | :summaryTableId: quarkus-mybatis-plus 3 | [.configuration-legend] 4 | icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime 5 | [.configuration-reference.searchable, cols="80,.^10,.^10"] 6 | |=== 7 | 8 | h|[[quarkus-mybatis-plus_configuration]]link:#quarkus-mybatis-plus_configuration[Configuration property] 9 | 10 | h|Type 11 | h|Default 12 | 13 | a|icon:lock[title=Fixed at build time] [[quarkus-mybatis-plus_quarkus.mybatis-plus.pagination.enabled]]`link:#quarkus-mybatis-plus_quarkus.mybatis-plus.pagination.enabled[quarkus.mybatis-plus.pagination.enabled]` 14 | 15 | [.description] 16 | -- 17 | MyBatis-plus PaginationInnerInterceptor 18 | 19 | ifdef::add-copy-button-to-env-var[] 20 | Environment variable: env_var_with_copy_button:+++QUARKUS_MYBATIS_PLUS_PAGINATION_ENABLED+++[] 21 | endif::add-copy-button-to-env-var[] 22 | ifndef::add-copy-button-to-env-var[] 23 | Environment variable: `+++QUARKUS_MYBATIS_PLUS_PAGINATION_ENABLED+++` 24 | endif::add-copy-button-to-env-var[] 25 | --|boolean 26 | |`true` 27 | 28 | 29 | a|icon:lock[title=Fixed at build time] [[quarkus-mybatis-plus_quarkus.mybatis-plus.sql-injector]]`link:#quarkus-mybatis-plus_quarkus.mybatis-plus.sql-injector[quarkus.mybatis-plus.sql-injector]` 30 | 31 | [.description] 32 | -- 33 | MyBatis-plus SqlInjector Class 34 | 35 | ifdef::add-copy-button-to-env-var[] 36 | Environment variable: env_var_with_copy_button:+++QUARKUS_MYBATIS_PLUS_SQL_INJECTOR+++[] 37 | endif::add-copy-button-to-env-var[] 38 | ifndef::add-copy-button-to-env-var[] 39 | Environment variable: `+++QUARKUS_MYBATIS_PLUS_SQL_INJECTOR+++` 40 | endif::add-copy-button-to-env-var[] 41 | --|string 42 | | 43 | 44 | 45 | a|icon:lock[title=Fixed at build time] [[quarkus-mybatis-plus_quarkus.mybatis-plus.meta-object-handler]]`link:#quarkus-mybatis-plus_quarkus.mybatis-plus.meta-object-handler[quarkus.mybatis-plus.meta-object-handler]` 46 | 47 | [.description] 48 | -- 49 | MyBatis-plus globalConfig metaObjectHandler 50 | 51 | ifdef::add-copy-button-to-env-var[] 52 | Environment variable: env_var_with_copy_button:+++QUARKUS_MYBATIS_PLUS_META_OBJECT_HANDLER+++[] 53 | endif::add-copy-button-to-env-var[] 54 | ifndef::add-copy-button-to-env-var[] 55 | Environment variable: `+++QUARKUS_MYBATIS_PLUS_META_OBJECT_HANDLER+++` 56 | endif::add-copy-button-to-env-var[] 57 | --|string 58 | | 59 | 60 | |=== -------------------------------------------------------------------------------- /mybatis-plus/docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | include::./includes/attributes.adoc[] 2 | = Quarkus - Using MyBatis Plus 3 | 4 | :extension-status: preview 5 | 6 | This guide demonstrates how your Quarkus application can use link:{mybatis-plus-root-url}[MyBatis Plus] to provide some efficient, useful, out-of-the-box features for link:{mybatis-root-url}[MyBatis], use it can effectively save your development time. 7 | -------------------------------------------------------------------------------- /mybatis-plus/docs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.mybatis 6 | quarkus-mybatis-plus-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-mybatis-plus-docs 12 | Quarkus - MyBatis Plus - Documentation 13 | 14 | 15 | 3.0.0 16 | 3.2.0 17 | 1.1.3 18 | 19 | 20 | 21 | 22 | 23 | io.quarkiverse.mybatis 24 | quarkus-mybatis-plus-deployment 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | 31 | 32 | it.ozimov 33 | yaml-properties-maven-plugin 34 | ${yaml-properties-maven-plugin.version} 35 | 36 | 37 | initialize 38 | 39 | read-project-properties 40 | 41 | 42 | 43 | ${project.basedir}/../../.github/project.yml 44 | 45 | 46 | 47 | 48 | 49 | 50 | maven-resources-plugin 51 | 52 | 53 | copy-resources 54 | generate-resources 55 | 56 | copy-resources 57 | 58 | 59 | ${project.basedir}/modules/ROOT/pages/includes/ 60 | 61 | 62 | ${project.basedir}/../target/asciidoc/generated/config/ 63 | quarkus-mybatis-plus.adoc 64 | false 65 | 66 | 67 | ${project.basedir}/templates/includes 68 | attributes.adoc 69 | true 70 | 71 | 72 | 73 | 74 | 75 | copy-images 76 | generate-resources 77 | 78 | copy-resources 79 | 80 | 81 | ${project.build.directory}/generated-docs/_images/ 82 | 83 | 84 | ${project.basedir}/modules/ROOT/assets/images/ 85 | false 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.asciidoctor 94 | asciidoctor-maven-plugin 95 | ${asciidoctor-maven-plugin.version} 96 | 97 | ${skipDocs} 98 | true 99 | 100 | 101 | WARN 102 | 103 | 104 | ${project.basedir}/modules/ROOT/pages/ 105 | true 106 | 107 | font 108 | 109 | ./_images/ 110 | true 111 | 112 | 113 | - 114 | true 115 | 116 | true 117 | 118 | 119 | 120 | 121 | output-html 122 | prepare-package 123 | 124 | process-asciidoc 125 | 126 | 127 | ${skipDocs} 128 | html5 129 | 130 | coderay 131 | 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.asciidoctor 141 | asciidoctorj 142 | ${asciidoctorj.version} 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /mybatis-plus/docs/templates/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :quarkus-version: ${quarkus.version} 2 | :quarkus-mybatis-plus-version: ${release.current-version} 3 | 4 | :mybatis-root-url: https://mybatis.org/mybatis-3/ 5 | :mybatis-plus-root-url: https://mybatis.plus/ 6 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.quarkiverse.mybatis 5 | quarkus-mybatis-plus-parent 6 | 999-SNAPSHOT 7 | ../ 8 | 9 | 4.0.0 10 | 11 | quarkus-mybatis-plus-integration-tests 12 | Quarkus - MyBatis Plus - Integration Tests 13 | The mybatis integration tests module 14 | 15 | 16 | 17 17 | 17 18 | true 19 | true 20 | ${skipTests} 21 | ${skipTests} 22 | 23 | 24 | 25 | 26 | io.quarkus 27 | quarkus-resteasy 28 | 29 | 30 | io.quarkus 31 | quarkus-resteasy-jackson 32 | 33 | 34 | io.quarkiverse.mybatis 35 | quarkus-mybatis-plus 36 | ${project.version} 37 | 38 | 39 | io.quarkus 40 | quarkus-jdbc-h2 41 | 42 | 43 | io.quarkus 44 | quarkus-jdbc-derby 45 | 46 | 47 | 48 | 49 | io.quarkus 50 | quarkus-junit5 51 | test 52 | 53 | 54 | io.rest-assured 55 | rest-assured 56 | test 57 | 58 | 59 | io.quarkus 60 | quarkus-test-h2 61 | test 62 | 63 | io.quarkus 64 | quarkus-test-derby 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | io.quarkus 73 | quarkus-maven-plugin 74 | ${quarkus.version} 75 | 76 | true 77 | ${quarkus.build.skip} 78 | 79 | 80 | 81 | 82 | build 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | native-image 93 | 94 | 95 | native 96 | 97 | 98 | 99 | native 100 | 101 | 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-failsafe-plugin 106 | 107 | 108 | 109 | integration-test 110 | verify 111 | 112 | 113 | 114 | ${project.build.directory}/${project.build.finalName}-runner 115 | org.jboss.logmanager.LogManager 116 | ${maven.home} 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/CustomBaseMapper.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.util.Collection; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | 7 | public interface CustomBaseMapper extends BaseMapper { 8 | 9 | Integer insertBatchSomeColumn(Collection entityList); 10 | } 11 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/EasySqlInjector.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.util.List; 4 | 5 | import com.baomidou.mybatisplus.core.injector.AbstractMethod; 6 | import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; 7 | import com.baomidou.mybatisplus.core.metadata.TableInfo; 8 | import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn; 9 | 10 | public class EasySqlInjector extends DefaultSqlInjector { 11 | @Override 12 | public List getMethodList(Class mapperClass, TableInfo tableInfo) { 13 | List methodList = super.getMethodList(mapperClass, tableInfo); 14 | methodList.add(new InsertBatchSomeColumn()); 15 | return methodList; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/MyBatisPlusResource.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.util.List; 4 | import java.util.UUID; 5 | 6 | import jakarta.inject.Inject; 7 | import jakarta.ws.rs.*; 8 | import jakarta.ws.rs.core.MediaType; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 14 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 15 | 16 | @Path("/mybatis/plus") 17 | public class MyBatisPlusResource { 18 | private Logger logger = LoggerFactory.getLogger(MyBatisPlusResource.class); 19 | @Inject 20 | UserMapper userMapper; 21 | 22 | @Path("/user/{id}") 23 | @GET 24 | @Produces(MediaType.APPLICATION_JSON) 25 | public User getUser(@PathParam("id") Integer id) { 26 | return userMapper.selectById(id); 27 | } 28 | 29 | @Path("/user") 30 | @POST 31 | @Produces(MediaType.TEXT_PLAIN) 32 | @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 33 | public Integer createUser(@FormParam("id") Integer id, @FormParam("name") String name, 34 | @FormParam("externalId") UUID externalId) { 35 | User user = new User(); 36 | user.setId(id); 37 | user.setName(name); 38 | user.setExternalId(externalId); 39 | return userMapper.insert(user); 40 | } 41 | 42 | @Path("/users") 43 | @POST 44 | @Consumes(MediaType.APPLICATION_JSON) 45 | public Integer createUsers(List users) { 46 | return userMapper.insertBatchSomeColumn(users); 47 | } 48 | 49 | @Path("/user/{id}") 50 | @DELETE 51 | @Produces(MediaType.TEXT_PLAIN) 52 | public Integer removeUser(@PathParam("id") Integer id) { 53 | return userMapper.deleteById(id); 54 | } 55 | 56 | @Path("/user/count/h2") 57 | @GET 58 | @Produces(MediaType.APPLICATION_JSON) 59 | public Long getUserCount() { 60 | return userMapper.selectCount(new QueryWrapper<>(new User())); 61 | } 62 | 63 | @Path("/user/page/{page}/{pageSize}") 64 | @GET 65 | public Page list(@PathParam("page") Integer page, @PathParam("pageSize") Integer pageSize) { 66 | return userMapper.selectPage(new Page(page, pageSize), null); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/MyObjectHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.ibatis.reflection.MetaObject; 6 | import org.jboss.logging.Logger; 7 | 8 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 9 | 10 | public class MyObjectHandler implements MetaObjectHandler { 11 | private static final Logger LOG = Logger.getLogger(MyObjectHandler.class); 12 | 13 | @Override 14 | public void insertFill(final MetaObject metaObject) { 15 | this.setFieldValByName("createTime", new Date().getTime(), metaObject); 16 | this.setFieldValByName("updateTime", new Date().getTime(), metaObject); 17 | } 18 | 19 | @Override 20 | public void updateFill(final MetaObject metaObject) { 21 | this.setFieldValByName("updateTime", new Date().getTime(), metaObject); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/MybatisPlusServiceResource.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.util.List; 4 | import java.util.UUID; 5 | 6 | import jakarta.inject.Inject; 7 | import jakarta.ws.rs.*; 8 | import jakarta.ws.rs.core.MediaType; 9 | 10 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 11 | 12 | @Path("/mybatis/plus/service") 13 | public class MybatisPlusServiceResource { 14 | @Inject 15 | UserServiceImpl userService; 16 | 17 | @Path("/user/{id}") 18 | @GET 19 | @Produces(MediaType.APPLICATION_JSON) 20 | public User getUser(@PathParam("id") Integer id) { 21 | return userService.getById(id); 22 | } 23 | 24 | @Path("/user") 25 | @POST 26 | @Produces(MediaType.TEXT_PLAIN) 27 | @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 28 | public Boolean createUser(@FormParam("id") Integer id, @FormParam("name") String name, 29 | @FormParam("externalId") UUID externalId) { 30 | User user = new User(); 31 | user.setId(id); 32 | user.setName(name); 33 | user.setExternalId(externalId); 34 | return userService.save(user); 35 | } 36 | 37 | @Path("/users") 38 | @POST 39 | @Consumes(MediaType.APPLICATION_JSON) 40 | public Boolean createUsers(List users) { 41 | return userService.saveBatch(users); 42 | } 43 | 44 | @Path("/user/{id}") 45 | @DELETE 46 | @Produces(MediaType.TEXT_PLAIN) 47 | public Boolean removeUser(@PathParam("id") Integer id) { 48 | return userService.removeById(id); 49 | } 50 | 51 | @Path("/user/count/h2") 52 | @GET 53 | @Produces(MediaType.APPLICATION_JSON) 54 | public Long getUserCount() { 55 | return userService.count(); 56 | } 57 | 58 | @Path("/user/page/{page}/{pageSize}") 59 | @GET 60 | public Page list(@PathParam("page") Integer page, @PathParam("pageSize") Integer pageSize) { 61 | return userService.page(new Page(page, pageSize), null); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/User.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | import com.baomidou.mybatisplus.annotation.FieldFill; 7 | import com.baomidou.mybatisplus.annotation.TableField; 8 | import com.baomidou.mybatisplus.annotation.TableName; 9 | import com.fasterxml.jackson.annotation.JsonInclude; 10 | 11 | @TableName("USERS") 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | public class User implements Serializable { 14 | private Integer id; 15 | private String name; 16 | private UUID externalId; 17 | @TableField(value = "create_time", fill = FieldFill.INSERT) 18 | private Long createTime; 19 | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) 20 | private Long updateTime; 21 | 22 | public Integer getId() { 23 | return id; 24 | } 25 | 26 | public void setId(Integer id) { 27 | this.id = id; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public void setName(String name) { 35 | this.name = name; 36 | } 37 | 38 | public UUID getExternalId() { 39 | return externalId; 40 | } 41 | 42 | public void setExternalId(UUID externalId) { 43 | this.externalId = externalId; 44 | } 45 | 46 | public Long getCreateTime() { 47 | return createTime; 48 | } 49 | 50 | public void setCreateTime(final Long createTime) { 51 | this.createTime = createTime; 52 | } 53 | 54 | public Long getUpdateTime() { 55 | return updateTime; 56 | } 57 | 58 | public void setUpdateTime(final Long updateTime) { 59 | this.updateTime = updateTime; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/UserMapper.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | 5 | @Mapper 6 | public interface UserMapper extends CustomBaseMapper { 7 | } 8 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | 5 | import io.quarkiverse.mybatis.plus.extension.service.impl.ServiceImpl; 6 | 7 | @ApplicationScoped 8 | public class UserServiceImpl extends ServiceImpl { 9 | } 10 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/java/io/quarkiverse/it/mybatis/plus/UuidTypeHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import java.sql.*; 4 | import java.util.UUID; 5 | 6 | import org.apache.ibatis.type.BaseTypeHandler; 7 | import org.apache.ibatis.type.JdbcType; 8 | import org.apache.ibatis.type.MappedTypes; 9 | 10 | @MappedTypes(UUID.class) 11 | public class UuidTypeHandler extends BaseTypeHandler { 12 | 13 | public static UUID fromStringAllowNulls(String uuid) { 14 | if (uuid == null || uuid.trim().equals("")) { 15 | return null; 16 | } else { 17 | return UUID.fromString(uuid); 18 | } 19 | } 20 | 21 | @Override 22 | public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException { 23 | // note the difference in how H2 wants to persist a UUID 24 | ps.setObject(i, parameter); 25 | } 26 | 27 | @Override 28 | public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 29 | return fromStringAllowNulls(rs.getString(columnName)); 30 | } 31 | 32 | @Override 33 | public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 34 | return fromStringAllowNulls(rs.getString(columnIndex)); 35 | } 36 | 37 | @Override 38 | public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 39 | return fromStringAllowNulls(cs.getString(columnIndex)); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # H2 2 | quarkus.datasource.db-kind=h2 3 | quarkus.datasource.username=username-default 4 | quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:default 5 | quarkus.mybatis.initial-sql=insert.sql 6 | quarkus.mybatis-plus.meta-object-handler=io.quarkiverse.it.mybatis.plus.MyObjectHandler 7 | quarkus.mybatis-plus.sql-injector=io.quarkiverse.it.mybatis.plus.EasySqlInjector 8 | 9 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/main/resources/insert.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE USERS IF EXISTS; 2 | DROP TABLE BOOKS IF EXISTS; 3 | 4 | CREATE TABLE USERS ( 5 | id integer not null primary key, 6 | name varchar(80) not null, 7 | externalId uuid not null, 8 | create_time long, 9 | update_time long 10 | ); 11 | 12 | CREATE TABLE BOOKS ( 13 | id integer not null primary key, 14 | title varchar(80) not null, 15 | author_id integer not null, 16 | 17 | foreign key(author_id) references USERS(id) 18 | ); 19 | 20 | DELETE FROM users; 21 | insert into users (id, name, externalId) values (1, 'Test User1', 'ccb16b65-8924-4c3f-8c55-681d85a16e79'); 22 | insert into users (id, name, externalId) values (2, 'Test User2', 'ae43f233-0b69-4c4e-bfa9-656c475150ad'); 23 | insert into users (id, name, externalId) values (3, 'Test User3', '5640e179-466c-427e-9747-4cfac09a2f9a'); 24 | 25 | DELETE from books; 26 | insert into books(id, title, author_id) values (1, 'Test Title', 1); 27 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/test/java/io/quarkiverse/it/mybatis/plus/MyBatisPlusIT.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import io.quarkus.test.junit.QuarkusIntegrationTest; 4 | 5 | @QuarkusIntegrationTest 6 | public class MyBatisPlusIT extends MyBatisPlusTest { 7 | } 8 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/test/java/io/quarkiverse/it/mybatis/plus/MyBatisPlusTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import static org.hamcrest.core.Is.is; 4 | import static org.hamcrest.core.IsNot.not; 5 | 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | import org.junit.jupiter.api.Test; 10 | 11 | import io.quarkus.test.junit.QuarkusTest; 12 | import io.restassured.RestAssured; 13 | import io.restassured.http.ContentType; 14 | 15 | @QuarkusTest 16 | public class MyBatisPlusTest { 17 | 18 | @Test 19 | public void test() { 20 | RestAssured.when().get("/mybatis/plus/user/1").then() 21 | .body(is("{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"}")); 22 | 23 | RestAssured.when().get("/mybatis/plus/user/page/1/2").then().assertThat() 24 | .body("records[0].name", is("Test User1")) 25 | .body("records[1].name", is("Test User2")) 26 | .body("total", is(3)) 27 | .body("size", is(2)) 28 | .body("current", is(1)) 29 | .body("pages", is(2)); 30 | 31 | RestAssured.given().param("id", "5") 32 | .param("name", "New User") 33 | .param("externalId", UUID.fromString("9b036c98-eb1d-4580-a8bb-1115d7a3cd44")) 34 | .post("/mybatis/plus/user") 35 | .then().body(is("1")); 36 | 37 | RestAssured.when().get("/mybatis/plus/user/5").then() 38 | .body("createTime", not(0)) 39 | .body("updateTime", not(0)); 40 | 41 | RestAssured.when().delete("/mybatis/plus/user/3").then() 42 | .body(is("1")); 43 | 44 | RestAssured.when().get("/mybatis/plus/user/count/h2").then() 45 | .body(is("3")); 46 | 47 | User user1 = new User(); 48 | user1.setId(100); 49 | user1.setName("Test User 100"); 50 | user1.setExternalId(UUID.randomUUID()); 51 | 52 | User user2 = new User(); 53 | user2.setId(101); 54 | user2.setName("Test User 101"); 55 | user2.setExternalId(UUID.randomUUID()); 56 | 57 | List users = List.of(user1, user2); 58 | RestAssured.given() 59 | .contentType(ContentType.JSON) 60 | .body(users) 61 | .post("/mybatis/plus/users") 62 | .then().body(is("2")); 63 | 64 | RestAssured.when().get("/mybatis/plus/user/count/h2").then() 65 | .body(is("5")); 66 | 67 | RestAssured.when().delete("/mybatis/plus/user/100").then() 68 | .body(is("1")); 69 | 70 | RestAssured.when().delete("/mybatis/plus/user/101").then() 71 | .body(is("1")); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/test/java/io/quarkiverse/it/mybatis/plus/MybatisPlusServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import static io.restassured.RestAssured.given; 4 | import static io.restassured.RestAssured.when; 5 | import static org.hamcrest.core.Is.is; 6 | import static org.hamcrest.core.IsNot.not; 7 | 8 | import java.net.URL; 9 | import java.util.List; 10 | import java.util.UUID; 11 | 12 | import org.junit.jupiter.api.Test; 13 | 14 | import io.quarkus.test.common.http.TestHTTPEndpoint; 15 | import io.quarkus.test.common.http.TestHTTPResource; 16 | import io.quarkus.test.junit.QuarkusTest; 17 | import io.restassured.http.ContentType; 18 | 19 | @QuarkusTest 20 | public class MybatisPlusServiceTest { 21 | 22 | @TestHTTPEndpoint(MybatisPlusServiceResource.class) 23 | @TestHTTPResource 24 | URL apiUrl; 25 | 26 | @Test 27 | public void test() { 28 | when().get(apiUrl + "/user/1").then() 29 | .statusCode(200) 30 | .body(is("{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"}")); 31 | 32 | when().get(apiUrl + "/user/page/1/2").then().assertThat() 33 | .body("records[0].name", is("Test User1")) 34 | .body("records[1].name", is("Test User2")) 35 | .body("total", is(3)) 36 | .body("size", is(2)) 37 | .body("current", is(1)) 38 | .body("pages", is(2)); 39 | 40 | given().param("id", "205") 41 | .param("name", "New User") 42 | .param("externalId", UUID.fromString("9b036c98-eb1d-4580-a8bb-1115d7a3cd44")) 43 | .post(apiUrl + "/user") 44 | .then().body(is("true")); 45 | 46 | when().get(apiUrl + "/user/205").then() 47 | .body("createTime", not(0)) 48 | .body("updateTime", not(0)); 49 | 50 | when().delete(apiUrl + "/user/205").then() 51 | .body(is("true")); 52 | 53 | when().get(apiUrl + "/user/count/h2").then() 54 | .body(is("3")); 55 | 56 | User user1 = new User(); 57 | user1.setId(200); 58 | user1.setName("Test User 200"); 59 | user1.setExternalId(UUID.randomUUID()); 60 | 61 | User user2 = new User(); 62 | user2.setId(201); 63 | user2.setName("Test User 201"); 64 | user2.setExternalId(UUID.randomUUID()); 65 | 66 | List users = List.of(user1, user2); 67 | given() 68 | .contentType(ContentType.JSON) 69 | .body(users) 70 | .post(apiUrl + "/users") 71 | .then().body(is("true")); 72 | 73 | when().get(apiUrl + "/user/count/h2").then() 74 | .body(is("5")); 75 | 76 | when().delete(apiUrl + "/user/200").then() 77 | .body(is("true")); 78 | 79 | when().delete(apiUrl + "/user/201").then() 80 | .body(is("true")); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /mybatis-plus/integration-tests/src/test/java/io/quarkiverse/it/mybatis/plus/TestResources.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis.plus; 2 | 3 | import io.quarkus.test.common.QuarkusTestResource; 4 | import io.quarkus.test.h2.H2DatabaseTestResource; 5 | 6 | @QuarkusTestResource(H2DatabaseTestResource.class) 7 | public class TestResources { 8 | } 9 | -------------------------------------------------------------------------------- /mybatis-plus/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.quarkiverse.mybatis 7 | quarkus-parent 8 | 999-SNAPSHOT 9 | 10 | 11 | quarkus-mybatis-plus-parent 12 | Quarkus - Mybatis Plus - Parent 13 | pom 14 | 15 | 16 | deployment 17 | runtime 18 | docs 19 | 20 | 21 | 22 | 23 | it 24 | 25 | 26 | performRelease 27 | !true 28 | 29 | 30 | 31 | integration-tests 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.quarkiverse.mybatis 5 | quarkus-mybatis-plus-parent 6 | 999-SNAPSHOT 7 | ../ 8 | 9 | 4.0.0 10 | 11 | quarkus-mybatis-plus 12 | Quarkus - Mybatis Plus - Runtime 13 | A powerful enhanced toolkit of MyBatis to simplify development 14 | 15 | 16 | 17 | io.quarkiverse.mybatis 18 | quarkus-mybatis 19 | ${project.version} 20 | 21 | 22 | com.baomidou 23 | mybatis-plus 24 | 25 | 26 | com.baomidou 27 | mybatis-plus-spring 28 | 29 | 30 | 31 | 32 | com.baomidou 33 | mybatis-plus-jsqlparser 34 | 35 | 36 | org.graalvm.sdk 37 | nativeimage 38 | 39 | 40 | ru.vyarus 41 | generics-resolver 42 | 43 | 44 | 45 | 46 | 47 | 48 | io.quarkus 49 | quarkus-extension-maven-plugin 50 | ${quarkus.version} 51 | 52 | 53 | 54 | extension-descriptor 55 | 56 | compile 57 | 58 | ${project.groupId}:${project.artifactId}-deployment:${project.version} 59 | 60 | 61 | 62 | 63 | 64 | 65 | maven-compiler-plugin 66 | 67 | 68 | 69 | io.quarkus 70 | quarkus-extension-processor 71 | ${quarkus.version} 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/com/baomidou/mybatisplus/core/metadata/MapperProxyMetadata.java: -------------------------------------------------------------------------------- 1 | package com.baomidou.mybatisplus.core.metadata; 2 | 3 | import org.apache.ibatis.reflection.MetaObject; 4 | import org.apache.ibatis.session.SqlSession; 5 | 6 | import com.baomidou.mybatisplus.core.override.MybatisMapperProxy; 7 | 8 | public class MapperProxyMetadata { 9 | private final SqlSession sqlSession; 10 | 11 | private final Class mapperInterface; 12 | 13 | public MapperProxyMetadata(MetaObject metaObject) { 14 | MybatisMapperProxy mapperProxy = (MybatisMapperProxy) metaObject.getOriginalObject(); 15 | this.mapperInterface = mapperProxy.getMapperInterface(); 16 | this.sqlSession = mapperProxy.getSqlSession(); 17 | } 18 | 19 | public Class getMapperInterface() { 20 | return mapperInterface; 21 | } 22 | 23 | public SqlSession getSqlSession() { 24 | return sqlSession; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "MapperProxy{" + 30 | "mapperInterface=" + mapperInterface + 31 | ", sqlSession=" + sqlSession + 32 | '}'; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/com/baomidou/mybatisplus/core/toolkit/reflect/SpringReflectionHelper.java: -------------------------------------------------------------------------------- 1 | package com.baomidou.mybatisplus.core.toolkit.reflect; 2 | 3 | public class SpringReflectionHelper { 4 | 5 | public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) { 6 | throw new RuntimeException("Not Supported"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/MyBatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus; 2 | 3 | import java.util.Optional; 4 | 5 | import io.quarkus.runtime.annotations.ConfigPhase; 6 | import io.quarkus.runtime.annotations.ConfigRoot; 7 | import io.smallrye.config.ConfigMapping; 8 | import io.smallrye.config.WithDefault; 9 | import io.smallrye.config.WithName; 10 | 11 | @ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) 12 | @ConfigMapping(prefix = "quarkus.mybatis-plus") 13 | public interface MyBatisPlusConfig { 14 | 15 | /** 16 | * MyBatis-plus PaginationInnerInterceptor 17 | */ 18 | @WithName("pagination.enabled") 19 | @WithDefault("true") 20 | boolean pageEnabled(); 21 | 22 | /** 23 | * MyBatis-plus SqlInjector Class 24 | */ 25 | @WithName("sql-injector") 26 | Optional sqlInjector(); 27 | 28 | /** 29 | * MyBatis-plus globalConfig metaObjectHandler 30 | */ 31 | @WithName("meta-object-handler") 32 | Optional metaObjectHandler(); 33 | } 34 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/QuarkusCompatibleSet.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import org.apache.ibatis.exceptions.PersistenceException; 6 | import org.apache.ibatis.logging.Log; 7 | import org.apache.ibatis.reflection.ExceptionUtil; 8 | import org.apache.ibatis.session.ExecutorType; 9 | import org.apache.ibatis.session.SqlSession; 10 | import org.apache.ibatis.session.SqlSessionFactory; 11 | 12 | import com.baomidou.mybatisplus.core.spi.CompatibleSet; 13 | import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; 14 | 15 | import io.quarkus.arc.Arc; 16 | import io.quarkus.arc.ClientProxy; 17 | import io.quarkus.runtime.annotations.RegisterForReflection; 18 | 19 | @RegisterForReflection 20 | public class QuarkusCompatibleSet implements CompatibleSet { 21 | 22 | @Override 23 | public SqlSession getSqlSession(SqlSessionFactory sessionFactory) { 24 | return Arc.container().instance(SqlSession.class).get(); 25 | } 26 | 27 | @Override 28 | public void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) { 29 | if (session != null) { 30 | session.close(); 31 | } 32 | } 33 | 34 | @Override 35 | public boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer consumer) { 36 | SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); 37 | try { 38 | consumer.accept(sqlSession); 39 | sqlSession.commit(true); 40 | return true; 41 | } catch (Throwable t) { 42 | sqlSession.rollback(); 43 | Throwable unwrapped = ExceptionUtil.unwrapThrowable(t); 44 | if (unwrapped instanceof PersistenceException) { 45 | throw ExceptionUtils.mpe(unwrapped); 46 | } 47 | throw ExceptionUtils.mpe(unwrapped); 48 | } finally { 49 | sqlSession.close(); 50 | } 51 | } 52 | 53 | @Override 54 | public T getBean(Class clz) { 55 | if (Arc.container() == null || !Arc.container().isRunning()) { 56 | return null; 57 | } 58 | return Arc.container().instance(clz).get(); 59 | } 60 | 61 | @Override 62 | public Object getProxyTargetObject(Object mapper) { 63 | Object result = mapper; 64 | //Quarkus's proxy detection 65 | while (result instanceof ClientProxy) { 66 | result = ((ClientProxy) result).arc_contextualInstance(); 67 | } 68 | return result; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/extension/repository/CrudRepository.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.extension.repository; 2 | 3 | import java.util.Collection; 4 | 5 | import jakarta.inject.Inject; 6 | import jakarta.transaction.Transactional; 7 | 8 | import org.apache.ibatis.binding.MapperMethod; 9 | 10 | import com.baomidou.mybatisplus.core.enums.SqlMethod; 11 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 12 | import com.baomidou.mybatisplus.core.metadata.TableInfo; 13 | import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; 14 | import com.baomidou.mybatisplus.core.toolkit.Assert; 15 | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; 16 | import com.baomidou.mybatisplus.core.toolkit.Constants; 17 | import com.baomidou.mybatisplus.core.toolkit.StringUtils; 18 | import com.baomidou.mybatisplus.extension.repository.AbstractRepository; 19 | import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; 20 | 21 | public abstract class CrudRepository, T> extends AbstractRepository { 22 | @Inject 23 | protected M baseMapper; 24 | 25 | @Override 26 | public M getBaseMapper() { 27 | Assert.notNull(this.baseMapper, "baseMapper can not be null"); 28 | return this.baseMapper; 29 | } 30 | 31 | @Transactional(rollbackOn = Exception.class) 32 | @Override 33 | public boolean saveBatch(Collection entityList, int batchSize) { 34 | String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE); 35 | return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity)); 36 | } 37 | 38 | protected String getSqlStatement(SqlMethod sqlMethod) { 39 | return SqlHelper.getSqlStatement(this.getMapperClass(), sqlMethod); 40 | } 41 | 42 | @Transactional(rollbackOn = Exception.class) 43 | @Override 44 | public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { 45 | TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass()); 46 | Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); 47 | String keyProperty = tableInfo.getKeyProperty(); 48 | Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); 49 | return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.getMapperClass(), this.log, entityList, batchSize, 50 | (sqlSession, entity) -> { 51 | Object idVal = tableInfo.getPropertyValue(entity, keyProperty); 52 | return StringUtils.checkValNull(idVal) 53 | || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity)); 54 | }, (sqlSession, entity) -> { 55 | MapperMethod.ParamMap param = new MapperMethod.ParamMap<>(); 56 | param.put(Constants.ENTITY, entity); 57 | sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param); 58 | }); 59 | } 60 | 61 | @Transactional(rollbackOn = Exception.class) 62 | @Override 63 | public boolean updateBatchById(Collection entityList, int batchSize) { 64 | String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID); 65 | return executeBatch(entityList, batchSize, (sqlSession, entity) -> { 66 | MapperMethod.ParamMap param = new MapperMethod.ParamMap<>(); 67 | param.put(Constants.ENTITY, entity); 68 | sqlSession.update(sqlStatement, param); 69 | }); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/extension/service/IService.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.extension.service; 2 | 3 | import java.util.Collection; 4 | 5 | import jakarta.transaction.Transactional; 6 | 7 | import com.baomidou.mybatisplus.extension.repository.IRepository; 8 | 9 | public interface IService extends IRepository { 10 | 11 | @Transactional(rollbackOn = Exception.class) 12 | default boolean saveBatch(Collection entityList) { 13 | return saveBatch(entityList, DEFAULT_BATCH_SIZE); 14 | } 15 | 16 | @Transactional(rollbackOn = Exception.class) 17 | default boolean saveOrUpdateBatch(Collection entityList) { 18 | return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE); 19 | } 20 | 21 | @Transactional(rollbackOn = Exception.class) 22 | default boolean removeBatchByIds(Collection list) { 23 | return removeByIds(list); 24 | } 25 | 26 | @Transactional(rollbackOn = Exception.class) 27 | default boolean updateBatchById(Collection entityList) { 28 | return updateBatchById(entityList, DEFAULT_BATCH_SIZE); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/extension/service/impl/ServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.extension.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | 5 | import io.quarkiverse.mybatis.plus.extension.repository.CrudRepository; 6 | import io.quarkiverse.mybatis.plus.extension.service.IService; 7 | 8 | public class ServiceImpl, T> extends CrudRepository implements IService { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/runtime/GenericTypeResolverImpl.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.runtime; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.baomidou.mybatisplus.core.toolkit.reflect.IGenericTypeResolver; 7 | 8 | import ru.vyarus.java.generics.resolver.GenericsResolver; 9 | import ru.vyarus.java.generics.resolver.context.GenericsContext; 10 | 11 | public class GenericTypeResolverImpl implements IGenericTypeResolver { 12 | private final Logger logger = LoggerFactory.getLogger(GenericTypeResolverImpl.class); 13 | 14 | @Override 15 | public Class[] resolveTypeArguments(Class clazz, Class genericIfc) { 16 | GenericsContext context = GenericsResolver.resolve(clazz) 17 | .type(genericIfc); 18 | return context.generics().toArray(new Class[] {}); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/runtime/MyBatisPlusConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.runtime; 2 | 3 | import org.apache.ibatis.session.Configuration; 4 | import org.jboss.logging.Logger; 5 | 6 | import com.baomidou.mybatisplus.core.MybatisConfiguration; 7 | import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils; 8 | 9 | import io.quarkiverse.mybatis.runtime.ConfigurationFactory; 10 | 11 | public class MyBatisPlusConfigurationFactory implements ConfigurationFactory { 12 | private static final Logger LOG = Logger.getLogger(MyBatisPlusConfigurationFactory.class); 13 | 14 | @Override 15 | public Configuration createConfiguration() { 16 | GenericTypeUtils.setGenericTypeResolver(new GenericTypeResolverImpl()); 17 | return new MybatisConfiguration(); 18 | } 19 | 20 | @Override 21 | public boolean isOverrideSetting() { 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/runtime/MyBatisPlusRecorder.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.runtime; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import org.apache.ibatis.io.Resources; 6 | import org.apache.ibatis.session.Configuration; 7 | import org.apache.ibatis.session.SqlSessionFactory; 8 | import org.jboss.logging.Logger; 9 | 10 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 11 | import com.baomidou.mybatisplus.core.injector.ISqlInjector; 12 | import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils; 13 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 14 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 15 | 16 | import io.quarkiverse.mybatis.plus.MyBatisPlusConfig; 17 | import io.quarkus.runtime.RuntimeValue; 18 | import io.quarkus.runtime.annotations.Recorder; 19 | 20 | @Recorder 21 | public class MyBatisPlusRecorder { 22 | private static final Logger LOG = Logger.getLogger(MyBatisPlusRecorder.class); 23 | 24 | public void initSqlSession(RuntimeValue sqlSessionFactory, MyBatisPlusConfig config) { 25 | Configuration configuration = sqlSessionFactory.getValue().getConfiguration(); 26 | 27 | if (config.pageEnabled()) { 28 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 29 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 30 | configuration.addInterceptor(interceptor); 31 | } 32 | 33 | if (config.metaObjectHandler().isPresent()) { 34 | try { 35 | String classMetaObjectHandler = config.metaObjectHandler().get(); 36 | MetaObjectHandler handler = (MetaObjectHandler) Resources.classForName(classMetaObjectHandler) 37 | .getDeclaredConstructor().newInstance(); 38 | GlobalConfigUtils.getGlobalConfig(configuration).setMetaObjectHandler(handler); 39 | } catch (Exception e) { 40 | LOG.warn("Can not initialize metaObjectHandler " + config.metaObjectHandler().get()); 41 | } 42 | } 43 | } 44 | 45 | public Consumer addCustomSqlInjector(MyBatisPlusConfig config) { 46 | return configuration -> { 47 | if (config.sqlInjector().isPresent()) { 48 | try { 49 | String classSqlInjector = config.sqlInjector().get(); 50 | ISqlInjector sqlInjector = (ISqlInjector) Resources.classForName(classSqlInjector) 51 | .getDeclaredConstructor().newInstance(); 52 | GlobalConfigUtils.getGlobalConfig(configuration).setSqlInjector(sqlInjector); 53 | } catch (Exception e) { 54 | LOG.warn("Can not initialize sqlInjector " + config.sqlInjector().get()); 55 | } 56 | } 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/java/io/quarkiverse/mybatis/plus/runtime/MyBatisPlusXMLConfigDelegateBuilder.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.plus.runtime; 2 | 3 | import java.io.Reader; 4 | 5 | import org.apache.ibatis.io.Resources; 6 | import org.apache.ibatis.session.Configuration; 7 | 8 | import com.baomidou.mybatisplus.core.MybatisXMLConfigBuilder; 9 | 10 | import io.quarkiverse.mybatis.runtime.XMLConfigDelegateBuilder; 11 | import io.quarkiverse.mybatis.runtime.config.MyBatisRuntimeConfig; 12 | 13 | public class MyBatisPlusXMLConfigDelegateBuilder implements XMLConfigDelegateBuilder { 14 | private MybatisXMLConfigBuilder builder; 15 | private MyBatisRuntimeConfig config; 16 | 17 | public MyBatisPlusXMLConfigDelegateBuilder() { 18 | 19 | } 20 | 21 | @Override 22 | public void setConfig(MyBatisRuntimeConfig config) { 23 | this.config = config; 24 | } 25 | 26 | @Override 27 | public Configuration getConfiguration() throws Exception { 28 | return getBuilder().getConfiguration(); 29 | } 30 | 31 | @Override 32 | public Configuration parse() throws Exception { 33 | return getBuilder().parse(); 34 | } 35 | 36 | private MybatisXMLConfigBuilder getBuilder() throws Exception { 37 | if (builder == null) { 38 | Reader reader = Resources.getResourceAsReader(config.xmlconfig().path()); 39 | builder = new MybatisXMLConfigBuilder(reader, config.environment()); 40 | } 41 | return builder; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/resources/META-INF/quarkus-extension.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "MyBatis Plus" 3 | metadata: 4 | icon-url: "https://mybatis.plus/img/logo.svg" 5 | keywords: 6 | - "mybatis-plus" 7 | guide: "https://quarkiverse.github.io/quarkiverse-docs/quarkus-mybatis/dev/" 8 | categories: 9 | - "data" 10 | status: "stable" 11 | -------------------------------------------------------------------------------- /mybatis-plus/runtime/src/main/resources/META-INF/services/com.baomidou.mybatisplus.core.spi.CompatibleSet: -------------------------------------------------------------------------------- 1 | io.quarkiverse.mybatis.plus.QuarkusCompatibleSet -------------------------------------------------------------------------------- /mybatis/README.md: -------------------------------------------------------------------------------- 1 | # Quarkus MyBatis Extension 2 | [![Build](https://github.com/quarkiverse/quarkus-mybatis/workflows/Build/badge.svg?branch=master)](https://github.com/quarkiverse/quarkus-mybatis/actions?query=workflow%3ABuild) 3 | [![License](https://img.shields.io/github/license/quarkiverse/quarkus-mybatis)](http://www.apache.org/licenses/LICENSE-2.0) 4 | [![Central](https://img.shields.io/maven-central/v/io.quarkiverse.mybatis/quarkus-mybatis-parent?color=green)](https://search.maven.org/search?q=g:io.quarkiverse.mybatis%20AND%20a:quarkus-mybatis-parent) 5 | 6 | [![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-) 7 | 8 | 9 | MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. This extension provides the developers ease of configuration and native support. Add the following dependency in your pom.xml to get started, 10 | 11 | ```xml 12 | 13 | io.quarkiverse.mybatis 14 | quarkus-mybatis 15 | 16 | ``` 17 | 18 | And then your can use the ```@Mapper``` in your application just like 19 | 20 | ```java 21 | @Mapper 22 | public interface UserMapper { 23 | 24 | @Select("SELECT * FROM USERS WHERE id = #{id}") 25 | User getUser(Integer id); 26 | 27 | @Insert("INSERT INTO USERS (id, name) VALUES (#{id}, #{name})") 28 | Integer createUser(@Param("id") Integer id, @Param("name") String name); 29 | 30 | @Delete("DELETE FROM USERS WHERE id = #{id}") 31 | Integer removeUser(Integer id); 32 | } 33 | ``` 34 | 35 | For more information and quickstart, you can check the complete [documentation](https://quarkiverse.github.io/quarkiverse-docs/quarkus-mybatis/dev/index.html). 36 | 37 | ## Contributors ✨ 38 | 39 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |

Amos Feng

💻 🚧

Chao

💻

Viktor Ilvovskyi

💻

Igor Dmitriev

💻

Ken Brumer

💻
53 | 54 | 55 | 56 | 57 | 58 | 59 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 60 | -------------------------------------------------------------------------------- /mybatis/deployment/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.quarkiverse.mybatis 5 | quarkus-mybatis-parent 6 | 999-SNAPSHOT 7 | ../ 8 | 9 | 4.0.0 10 | 11 | quarkus-mybatis-deployment 12 | Quarkus - Mybatis - Deployment 13 | 14 | 15 | 16 | io.quarkus 17 | quarkus-arc-deployment 18 | 19 | 20 | io.quarkus 21 | quarkus-agroal-deployment 22 | 23 | 24 | io.quarkiverse.mybatis 25 | quarkus-mybatis 26 | ${project.version} 27 | 28 | 29 | 30 | io.quarkus 31 | quarkus-junit5-internal 32 | test 33 | 34 | 35 | io.quarkus 36 | quarkus-test-h2 37 | test 38 | 39 | 40 | io.quarkus 41 | quarkus-test-derby 42 | test 43 | 44 | 45 | io.quarkus 46 | quarkus-jdbc-h2-deployment 47 | test 48 | 49 | 50 | io.quarkus 51 | quarkus-jdbc-derby 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | maven-compiler-plugin 60 | 61 | 62 | 63 | io.quarkus 64 | quarkus-extension-processor 65 | ${quarkus.version} 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/ConfigurationCustomizerBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import org.apache.ibatis.session.Configuration; 6 | 7 | import io.quarkus.builder.item.MultiBuildItem; 8 | 9 | public final class ConfigurationCustomizerBuildItem extends MultiBuildItem { 10 | private Consumer customizer; 11 | 12 | public ConfigurationCustomizerBuildItem(Consumer customizer) { 13 | this.customizer = customizer; 14 | } 15 | 16 | public Consumer getCustomizer() { 17 | return customizer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/ConfigurationFactoryBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import io.quarkiverse.mybatis.runtime.ConfigurationFactory; 4 | import io.quarkus.builder.item.SimpleBuildItem; 5 | 6 | public final class ConfigurationFactoryBuildItem extends SimpleBuildItem { 7 | private final ConfigurationFactory factory; 8 | 9 | public ConfigurationFactoryBuildItem(ConfigurationFactory factory) { 10 | this.factory = factory; 11 | } 12 | 13 | public ConfigurationFactory getFactory() { 14 | return factory; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/MyBatisMappedJdbcTypeBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import org.jboss.jandex.DotName; 4 | 5 | import io.quarkus.builder.item.MultiBuildItem; 6 | 7 | public final class MyBatisMappedJdbcTypeBuildItem extends MultiBuildItem { 8 | private final DotName mappedJdbcTypeName; 9 | 10 | public MyBatisMappedJdbcTypeBuildItem(DotName mappedJdbcTypeName) { 11 | this.mappedJdbcTypeName = mappedJdbcTypeName; 12 | } 13 | 14 | public DotName getMappedJdbcTypeName() { 15 | return mappedJdbcTypeName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/MyBatisMappedTypeBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import org.jboss.jandex.DotName; 4 | 5 | import io.quarkus.builder.item.MultiBuildItem; 6 | 7 | public final class MyBatisMappedTypeBuildItem extends MultiBuildItem { 8 | private final DotName mappedTypeName; 9 | 10 | public MyBatisMappedTypeBuildItem(DotName mappedTypeName) { 11 | this.mappedTypeName = mappedTypeName; 12 | } 13 | 14 | public DotName getMappedTypeName() { 15 | return mappedTypeName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/MyBatisMapperBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import org.jboss.jandex.DotName; 4 | 5 | import io.quarkus.builder.item.MultiBuildItem; 6 | 7 | public final class MyBatisMapperBuildItem extends MultiBuildItem { 8 | private final DotName mapperName; 9 | private final String dataSourceName; 10 | 11 | public MyBatisMapperBuildItem(DotName mapperName, String dataSourceName) { 12 | this.mapperName = mapperName; 13 | this.dataSourceName = dataSourceName; 14 | } 15 | 16 | public DotName getMapperName() { 17 | return mapperName; 18 | } 19 | 20 | public String getDataSourceName() { 21 | return dataSourceName; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/MyBatisXmlConfigBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import io.quarkus.builder.item.SimpleBuildItem; 4 | 5 | public final class MyBatisXmlConfigBuildItem extends SimpleBuildItem { 6 | private final boolean enabled; 7 | private final String name; 8 | 9 | public MyBatisXmlConfigBuildItem(String name, boolean enabled) { 10 | this.name = name; 11 | this.enabled = enabled; 12 | } 13 | 14 | public boolean isEnabled() { 15 | return enabled; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/SqlSessionFactoryBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import org.apache.ibatis.session.SqlSessionFactory; 4 | 5 | import io.quarkus.builder.item.MultiBuildItem; 6 | import io.quarkus.runtime.RuntimeValue; 7 | 8 | /** 9 | * Hold the RuntimeValue of {@link SqlSessionFactory} 10 | */ 11 | public final class SqlSessionFactoryBuildItem extends MultiBuildItem { 12 | private final RuntimeValue sqlSessionFactory; 13 | private final String dataSourceName; 14 | private final boolean defaultDataSource; 15 | private final boolean fromXmlConfig; 16 | 17 | public SqlSessionFactoryBuildItem( 18 | RuntimeValue sqlSessionFactory, 19 | String dataSourceName, 20 | boolean isDefaultDataSource, 21 | boolean isFromXmlConfig) { 22 | this.sqlSessionFactory = sqlSessionFactory; 23 | this.dataSourceName = dataSourceName; 24 | this.defaultDataSource = isDefaultDataSource; 25 | this.fromXmlConfig = isFromXmlConfig; 26 | } 27 | 28 | public RuntimeValue getSqlSessionFactory() { 29 | return sqlSessionFactory; 30 | } 31 | 32 | public String getDataSourceName() { 33 | return dataSourceName; 34 | } 35 | 36 | public boolean isDefaultDataSource() { 37 | return defaultDataSource; 38 | } 39 | 40 | public boolean isFromXmlConfig() { 41 | return fromXmlConfig; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/SqlSessionFactoryBuilderBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 4 | 5 | import io.quarkus.builder.item.SimpleBuildItem; 6 | 7 | public final class SqlSessionFactoryBuilderBuildItem extends SimpleBuildItem { 8 | private final SqlSessionFactoryBuilder builder; 9 | 10 | public SqlSessionFactoryBuilderBuildItem(SqlSessionFactoryBuilder builder) { 11 | this.builder = builder; 12 | } 13 | 14 | public SqlSessionFactoryBuilder getBuilder() { 15 | return builder; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/SqlSessionManagerBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import io.quarkiverse.mybatis.runtime.TransactionalSqlSession; 4 | import io.quarkus.builder.item.MultiBuildItem; 5 | import io.quarkus.runtime.RuntimeValue; 6 | 7 | /** 8 | * Hold the RuntimeValue of {@link TransactionalSqlSession} 9 | */ 10 | public final class SqlSessionManagerBuildItem extends MultiBuildItem { 11 | private final RuntimeValue sqlSessionManager; 12 | private final String dataSourceName; 13 | private final boolean defaultDataSource; 14 | 15 | public SqlSessionManagerBuildItem( 16 | RuntimeValue sqlSessionManager, 17 | String dataSourceName, 18 | Boolean defaultDataSource) { 19 | this.sqlSessionManager = sqlSessionManager; 20 | this.dataSourceName = dataSourceName; 21 | this.defaultDataSource = defaultDataSource; 22 | } 23 | 24 | public RuntimeValue getSqlSessionManager() { 25 | return sqlSessionManager; 26 | } 27 | 28 | public String getDataSourceName() { 29 | return dataSourceName; 30 | } 31 | 32 | public boolean isDefaultDataSource() { 33 | return defaultDataSource; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mybatis/deployment/src/main/java/io/quarkiverse/mybatis/deployment/XMLConfigBuilderBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.deployment; 2 | 3 | import io.quarkiverse.mybatis.runtime.XMLConfigDelegateBuilder; 4 | import io.quarkus.builder.item.SimpleBuildItem; 5 | 6 | public final class XMLConfigBuilderBuildItem extends SimpleBuildItem { 7 | private final XMLConfigDelegateBuilder builder; 8 | 9 | public XMLConfigBuilderBuildItem(XMLConfigDelegateBuilder builder) { 10 | this.builder = builder; 11 | } 12 | 13 | public XMLConfigDelegateBuilder getBuilder() { 14 | return builder; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/java/io/quarkiverse/mybatis/test/MyBatisTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.test; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.util.UUID; 7 | 8 | import jakarta.inject.Inject; 9 | import jakarta.inject.Named; 10 | 11 | import org.apache.ibatis.session.SqlSessionFactory; 12 | import org.jboss.shrinkwrap.api.ShrinkWrap; 13 | import org.jboss.shrinkwrap.api.spec.JavaArchive; 14 | import org.junit.jupiter.api.Test; 15 | import org.junit.jupiter.api.extension.RegisterExtension; 16 | 17 | import io.quarkus.test.QuarkusUnitTest; 18 | 19 | public class MyBatisTest { 20 | @RegisterExtension 21 | static final QuarkusUnitTest config = new QuarkusUnitTest().withConfigurationResource("application.properties") 22 | .setArchiveProducer( 23 | () -> ShrinkWrap.create(JavaArchive.class) 24 | .addClasses(UserMapper.class, User.class, UuidTypeHandler.class, UuidJdbcTypeHandler.class)); 25 | 26 | @Inject 27 | UserMapper userMapper; 28 | 29 | @Inject 30 | SqlSessionFactory h2SqlSessionFactory; 31 | 32 | @Named("derby") 33 | SqlSessionFactory derbySqlSessionFactory; 34 | 35 | @Test 36 | public void test() throws Exception { 37 | assertTrue(h2SqlSessionFactory.getConfiguration().getMapperRegistry().hasMapper(UserMapper.class)); 38 | assertEquals("H2", h2SqlSessionFactory.openSession().getConnection().getMetaData().getDatabaseProductName()); 39 | User user = userMapper.getUser(1); 40 | assertEquals(user.getId(), 1); 41 | assertEquals(user.getName(), "Test User1"); 42 | assertEquals(user.getExternalId(), UUID.fromString("8c5034fe-1a00-43b7-9c75-f83ef14e3507")); 43 | 44 | assertEquals("Apache Derby", 45 | derbySqlSessionFactory.openSession().getConnection().getMetaData().getDatabaseProductName()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/java/io/quarkiverse/mybatis/test/TestResources.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.test; 2 | 3 | import io.quarkus.test.common.QuarkusTestResource; 4 | import io.quarkus.test.derby.DerbyDatabaseTestResource; 5 | import io.quarkus.test.h2.H2DatabaseTestResource; 6 | 7 | @QuarkusTestResource(H2DatabaseTestResource.class) 8 | @QuarkusTestResource(DerbyDatabaseTestResource.class) 9 | public class TestResources { 10 | } 11 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/java/io/quarkiverse/mybatis/test/User.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.test; 2 | 3 | import java.util.UUID; 4 | 5 | public class User { 6 | private Integer id; 7 | private String name; 8 | private UUID externalId; 9 | 10 | public Integer getId() { 11 | return id; 12 | } 13 | 14 | public void setId(Integer id) { 15 | this.id = id; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public void setName(String name) { 23 | this.name = name; 24 | } 25 | 26 | public UUID getExternalId() { 27 | return externalId; 28 | } 29 | 30 | public void setExternalId(UUID externalId) { 31 | this.externalId = externalId; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "User{" + 37 | "id=" + id + 38 | ", name='" + name + '\'' + 39 | ", externalId=" + externalId + 40 | '}'; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/java/io/quarkiverse/mybatis/test/UserMapper.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.test; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.apache.ibatis.annotations.Select; 5 | 6 | @Mapper 7 | public interface UserMapper { 8 | 9 | @Select("select * from users where id = #{id}") 10 | User getUser(Integer id); 11 | } 12 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/java/io/quarkiverse/mybatis/test/UuidJdbcTypeHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.test; 2 | 3 | import java.sql.*; 4 | import java.util.UUID; 5 | 6 | import org.apache.ibatis.type.BaseTypeHandler; 7 | import org.apache.ibatis.type.JdbcType; 8 | import org.apache.ibatis.type.MappedJdbcTypes; 9 | 10 | @MappedJdbcTypes(value = JdbcType.OTHER, includeNullJdbcType = true) 11 | public class UuidJdbcTypeHandler extends BaseTypeHandler { 12 | 13 | public static UUID fromStringAllowNulls(String uuid) { 14 | if (uuid == null || uuid.trim().equals("")) { 15 | return null; 16 | } else { 17 | return UUID.fromString(uuid); 18 | } 19 | } 20 | 21 | @Override 22 | public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException { 23 | ps.setObject(i, parameter.toString(), Types.OTHER); 24 | } 25 | 26 | @Override 27 | public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 28 | return fromStringAllowNulls(rs.getString(columnName)); 29 | } 30 | 31 | @Override 32 | public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 33 | return fromStringAllowNulls(rs.getString(columnIndex)); 34 | } 35 | 36 | @Override 37 | public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 38 | return fromStringAllowNulls(cs.getString(columnIndex)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/java/io/quarkiverse/mybatis/test/UuidTypeHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.test; 2 | 3 | import java.sql.*; 4 | import java.util.UUID; 5 | 6 | import org.apache.ibatis.type.BaseTypeHandler; 7 | import org.apache.ibatis.type.JdbcType; 8 | import org.apache.ibatis.type.MappedTypes; 9 | 10 | @MappedTypes(UUID.class) 11 | public class UuidTypeHandler extends BaseTypeHandler { 12 | 13 | public static UUID fromStringAllowNulls(String uuid) { 14 | if (uuid == null || uuid.trim().equals("")) { 15 | return null; 16 | } else { 17 | return UUID.fromString(uuid); 18 | } 19 | } 20 | 21 | @Override 22 | public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException { 23 | ps.setObject(i, parameter.toString(), Types.OTHER); 24 | } 25 | 26 | @Override 27 | public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 28 | return fromStringAllowNulls(rs.getString(columnName)); 29 | } 30 | 31 | @Override 32 | public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 33 | return fromStringAllowNulls(rs.getString(columnIndex)); 34 | } 35 | 36 | @Override 37 | public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 38 | return fromStringAllowNulls(cs.getString(columnIndex)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | # H2 2 | quarkus.datasource.db-kind=h2 3 | quarkus.datasource.username=username-default 4 | quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:default 5 | quarkus.mybatis.initial-sql=insert.sql 6 | 7 | # Derby 8 | quarkus.datasource.derby.db-kind=derby 9 | quarkus.datasource.derby.jdbc.url=jdbc:derby://localhost:1527/memory:testDB;create=true 10 | -------------------------------------------------------------------------------- /mybatis/deployment/src/test/resources/insert.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE USERS ( 2 | id integer not null primary key, 3 | name varchar(80) not null, 4 | externalId uuid not null 5 | ); 6 | 7 | DELETE FROM users; 8 | insert into users (id, name, externalId) values (1, 'Test User1', '8c5034fe-1a00-43b7-9c75-f83ef14e3507'); 9 | insert into users (id, name, externalId) values (2, 'Test User2', '0a197020-e05a-41ab-9c46-649cd432feb4'); 10 | insert into users (id, name, externalId) values (3, 'Test User3', '9b54c1b1-5e7d-4a64-a06c-9a5b9531e2ee'); 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /mybatis/docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: quarkus-mybatis 2 | title: MyBatis 3 | version: dev 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | -------------------------------------------------------------------------------- /mybatis/docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Introduction] 2 | -------------------------------------------------------------------------------- /mybatis/docs/modules/ROOT/pages/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :quarkus-version: 3.18.2 2 | :quarkus-mybatis-version: 2.2.4 3 | 4 | :mybatis-root-url: https://mybatis.org/mybatis-3/ 5 | -------------------------------------------------------------------------------- /mybatis/docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | include::./includes/attributes.adoc[] 2 | = Quarkus - Using MyBatis 3 | 4 | :extension-status: preview 5 | 6 | This guide demonstrates how your Quarkus application can use link:{mybatis-root-url}[MyBatis] to support custom SQL, stored procedures and advanced mappings. 7 | 8 | == Prerequisites 9 | 10 | To complete this guide, you need: 11 | 12 | * less than 15 minutes 13 | * an IDE 14 | * JDK 11+ installed with `JAVA_HOME` configured appropriately 15 | * Apache Maven 16 | * A running Mysql Database server 17 | * GraalVM, or Docker, installed if you want to run in native mode. 18 | 19 | == Architecture 20 | 21 | The application built in this guide is quite simple: the user can get, add and remove a record through the RESTful API by using the MyBatis Mapper. 22 | 23 | 24 | == Solution 25 | 26 | We recommend that you follow the instructions in the next sections and create the application step by step. 27 | 28 | == Creating the Maven Project 29 | 30 | First, we need a new project. Create a new project with the following command: 31 | 32 | [source, bash, subs=attributes+] 33 | ---- 34 | mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \ 35 | -DprojectGroupId=org.acme \ 36 | -DprojectArtifactId=mybatis-quickstart \ 37 | -Dextensions="resteasy-jackson,jdbc-mysql,io.quarkiverse.mybatis:quarkus-mybatis:{quarkus-mybatis-version}" \ 38 | -DnoExamples 39 | cd mybatis-quickstart 40 | ---- 41 | 42 | [TIP] 43 | ==== 44 | Maven 3.6.2+ is required for this to work. 45 | ==== 46 | 47 | This command generates a Maven project, with its pom.xml importing the quarkus-mybatis extension. 48 | 49 | If you already have your Quarkus project configured, you can add the `quarkus-mybatis` extension 50 | to your project by adding the following dependency in your `pom.xml`: 51 | 52 | [source, subs=attributes+] 53 | ---- 54 | 55 | io.quarkiverse.mybatis 56 | quarkus-mybatis 57 | {quarkus-mybatis-version} 58 | 59 | ---- 60 | 61 | == Creating the User POJO 62 | We are going to create a `User` POJO to access to the data in the backend mysql server. 63 | Create the `src/main/java/org/acme/mybatis/User.java` file, with the following content: 64 | 65 | [source, java] 66 | ---- 67 | package org.acme.mybatis; 68 | 69 | public class User { 70 | private Integer id; 71 | private String name; 72 | 73 | public Integer getId() { 74 | return id; 75 | } 76 | 77 | public void setId(Integer id) { 78 | this.id = id; 79 | } 80 | 81 | public String getName() { 82 | return name; 83 | } 84 | 85 | public void setName(String name) { 86 | this.name = name; 87 | } 88 | } 89 | ---- 90 | 91 | == Creating the User Mapper 92 | We are going to create a `UserMapper` class which will use the MyBatis annotations to inject the SQL. 93 | Create the `src/main/java/org/acme/mybatis/UserMapper.java` file, with the following content: 94 | 95 | [source, java] 96 | ---- 97 | package org.acme.mybatis; 98 | 99 | import org.apache.ibatis.annotations.Delete; 100 | import org.apache.ibatis.annotations.Insert; 101 | import org.apache.ibatis.annotations.Mapper; 102 | import org.apache.ibatis.annotations.Param; 103 | import org.apache.ibatis.annotations.Select; 104 | 105 | @Mapper 106 | public interface UserMapper { 107 | 108 | @Select("SELECT * FROM USERS WHERE id = #{id}") 109 | User getUser(Integer id); // <1> 110 | 111 | @Insert("INSERT INTO USERS (id, name) VALUES (#{id}, #{name})") 112 | Integer createUser(@Param("id") Integer id, @Param("name") String name); // <2> 113 | 114 | @Delete("DELETE FROM USERS WHERE id = #{id}") 115 | Integer removeUser(Integer id); // <3> 116 | } 117 | ---- 118 | 119 | 1. Get a user from the database. 120 | 2. Insert a user into the database. We should use the `@Param` to bind the parameters. 121 | 3. Delete a user from the databse. 122 | 123 | == Creating the MyBatisResource to handle the requests 124 | We are going to create a `MyBatisResource` class which will handle all the requests to create, query or remove the data 125 | from the database. 126 | 127 | [source, java] 128 | ---- 129 | package org.acme.mybatis; 130 | 131 | import jakarta.inject.Inject; 132 | import jakarta.ws.rs.Consumes; 133 | import jakarta.ws.rs.DELETE; 134 | import jakarta.ws.rs.FormParam; 135 | import jakarta.ws.rs.GET; 136 | import jakarta.ws.rs.POST; 137 | import jakarta.ws.rs.Path; 138 | import jakarta.ws.rs.PathParam; 139 | import jakarta.ws.rs.Produces; 140 | import jakarta.ws.rs.core.MediaType; 141 | 142 | @Path("/mybatis") 143 | public class MyBatisResource { 144 | 145 | @Inject 146 | UserMapper userMapper; // <1> 147 | 148 | @Path("/user/{id}") 149 | @GET 150 | @Produces(MediaType.APPLICATION_JSON) 151 | public User getUser(@PathParam("id") Integer id) { 152 | return userMapper.getUser(id); 153 | } 154 | 155 | @Path("/user") 156 | @POST 157 | @Produces(MediaType.TEXT_PLAIN) 158 | @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 159 | public Integer createUser(@FormParam("id") Integer id, @FormParam("name") String name) { 160 | return userMapper.createUser(id, name); 161 | } 162 | 163 | @Path("/user/{id}") 164 | @DELETE 165 | @Produces(MediaType.TEXT_PLAIN) 166 | public Integer removeUser(@PathParam("id") Integer id) { 167 | return userMapper.removeUser(id); 168 | } 169 | } 170 | ---- 171 | 1. It uses the UserMapper which should be injected by the Quarkus to access the database. 172 | 173 | == Configure the properties 174 | 175 | We need to config the datasource used to connect to the database and the mybatis will choose the default one. Also you 176 | can use ```quarkus.mybatis.datasource``` for the specific database. 177 | 178 | [source] 179 | ---- 180 | quarkus.datasource.db-kind=mysql 181 | quarkus.datasource.username= 182 | 183 | quarkus.datasource.jdbc.url=jdbc:mysql://localhost/test #<1> 184 | quarkus.mybatis.initial-sql=insert.sql #<2> 185 | ---- 186 | 187 | 1. The datasource used by the mybatis to connect the database. 188 | 2. The SQL file which should be executed just after the application is started. 189 | 190 | We could keep the following content in the `insert.sql` to add some data: 191 | [source, sql] 192 | ---- 193 | DROP TABLE IF EXISTS USERS; 194 | 195 | CREATE TABLE USERS ( 196 | id integer not null primary key, 197 | name varchar(80) not null 198 | ); 199 | 200 | INSERT INTO USERS (id, name) values(1, 'Test User1'); 201 | INSERT INTO USERS (id, name) values(2, 'Test User2'); 202 | INSERT INTO USERS (id, name) values(3, 'Test User3'); 203 | ---- 204 | 205 | == Running with the JVM mode 206 | At first, you should make sure the Mysql Server is running and the `test` database has been created. 207 | Then, you just need to run: 208 | 209 | [source, shell] 210 | ---- 211 | ./mvnw compile quarkus:dev 212 | ---- 213 | 214 | You can get the user by using the following command: 215 | 216 | [source, shell] 217 | ---- 218 | curl http://localhost:8080/mybatis/user/1 219 | ---- 220 | 221 | Or create a new user: 222 | 223 | [source, shell] 224 | ---- 225 | curl -X POST http://localhost:8080/mybatis/user -d 'id=4&name=test' 226 | ---- 227 | 228 | Or remove a user: 229 | 230 | [source, shell] 231 | ---- 232 | curl -X DELETE http://localhost:8080/mybatis/user/1 233 | ---- 234 | 235 | == Running Native 236 | You can build the native executable with: 237 | 238 | [source, shell] 239 | ---- 240 | ./mvnw package -Pnative 241 | ---- 242 | 243 | and then run with: 244 | 245 | [source, shell] 246 | ---- 247 | ./target/mybatis-quickstart-1.0-SNAPSHOT-runner 248 | ---- 249 | 250 | == Support for multiple data sources 251 | You can choose a specific data source for MyBatis mapper using the annotation `@MapperDataSource`. 252 | Query in the next example will be running against data source with name `user`. 253 | If there is no such annotation on the mapper, the default data source will be used. 254 | 255 | [source, java] 256 | ---- 257 | @Mapper 258 | @MapperDataSource("user") 259 | public interface UserMapper { 260 | @Select("SELECT * FROM USERS WHERE id = #{id}") 261 | User getUser(Integer id); 262 | } 263 | ---- 264 | 265 | == CDI integration 266 | Injects default session factory: 267 | 268 | [source, java] 269 | ---- 270 | @Inject 271 | SqlSessionFactory sqlSessionFactory; 272 | ---- 273 | 274 | Injects session factory for data source `user`: 275 | 276 | [source, java] 277 | ---- 278 | @Named("user") 279 | SqlSessionFactory sqlSessionFactory; 280 | ---- 281 | 282 | == XML Configuration Support 283 | 284 | You need to set ```quarkus.mybatis.xmlconfig.enable``` to ```true``` and set ```quarkus.mybatis.xmlconfig.path``` to the 285 | mybatis xml configuration which the default value is ```mybatis-config.xml```. 286 | Aslo ```quarkus.mybatis.environment``` is relevant to the element of ```environment``` in the xml configuration file. 287 | 288 | [source, text] 289 | ---- 290 | # H2 291 | quarkus.datasource.h2.db-kind=h2 292 | quarkus.datasource.h2.username=sa 293 | quarkus.datasource.h2.password=sa 294 | quarkus.datasource.h2.jdbc.url=jdbc:h2:tcp://localhost/mem:default 295 | 296 | # MyBatis 297 | quarkus.mybatis.xmlconfig.enable=true 298 | quarkus.mybatis.xmlconfig.path=mybatis-config.xml 299 | quarkus.mybatis.environment=development 300 | quarkus.mybatis.h2.initial-sql=insert-h2.sql 301 | ---- 302 | 303 | [source, xml] 304 | ---- 305 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | ---- 329 | 330 | The dataSource type must be ```QUARKUS``` and the property ```db``` could be specified to the datasource name in the 331 | quarkus configuration. 332 | 333 | 334 | == Configuration References 335 | include::includes/quarkus-mybatis.adoc[opts=optional, leveloffset=+1] 336 | -------------------------------------------------------------------------------- /mybatis/docs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.mybatis 6 | quarkus-mybatis-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-mybatis-docs 12 | Quarkus - MyBatis - Documentation 13 | 14 | 15 | 3.0.0 16 | 3.2.0 17 | 1.1.3 18 | 19 | 20 | 21 | 22 | 23 | io.quarkiverse.mybatis 24 | quarkus-mybatis-deployment 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | 31 | 32 | it.ozimov 33 | yaml-properties-maven-plugin 34 | ${yaml-properties-maven-plugin.version} 35 | 36 | 37 | initialize 38 | 39 | read-project-properties 40 | 41 | 42 | 43 | ${project.basedir}/../../.github/project.yml 44 | 45 | 46 | 47 | 48 | 49 | 50 | maven-resources-plugin 51 | 52 | 53 | copy-resources 54 | generate-resources 55 | 56 | copy-resources 57 | 58 | 59 | ${project.basedir}/modules/ROOT/pages/includes/ 60 | 61 | 62 | ${project.basedir}/../target/asciidoc/generated/config/ 63 | quarkus-mybatis.adoc 64 | false 65 | 66 | 67 | ${project.basedir}/templates/includes 68 | attributes.adoc 69 | true 70 | 71 | 72 | 73 | 74 | 75 | copy-images 76 | generate-resources 77 | 78 | copy-resources 79 | 80 | 81 | ${project.build.directory}/generated-docs/_images/ 82 | 83 | 84 | ${project.basedir}/modules/ROOT/assets/images/ 85 | false 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.asciidoctor 94 | asciidoctor-maven-plugin 95 | ${asciidoctor-maven-plugin.version} 96 | 97 | ${skipDocs} 98 | true 99 | 100 | 101 | WARN 102 | 103 | 104 | ${project.basedir}/modules/ROOT/pages/ 105 | true 106 | 107 | font 108 | 109 | ./_images/ 110 | true 111 | 112 | 113 | - 114 | true 115 | 116 | true 117 | 118 | 119 | 120 | 121 | output-html 122 | prepare-package 123 | 124 | process-asciidoc 125 | 126 | 127 | ${skipDocs} 128 | html5 129 | 130 | coderay 131 | 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.asciidoctor 141 | asciidoctorj 142 | ${asciidoctorj.version} 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /mybatis/docs/templates/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :quarkus-version: ${quarkus.version} 2 | :quarkus-mybatis-version: ${release.current-version} 3 | 4 | :mybatis-root-url: https://mybatis.org/mybatis-3/ 5 | -------------------------------------------------------------------------------- /mybatis/integration-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.quarkiverse.mybatis 5 | quarkus-mybatis-parent 6 | 999-SNAPSHOT 7 | ../ 8 | 9 | 4.0.0 10 | 11 | quarkus-mybatis-integration-tests 12 | Quarkus - MyBatis - Integration Tests 13 | The mybatis integration tests module 14 | 15 | 16 | true 17 | true 18 | ${skipTests} 19 | ${skipTests} 20 | 21 | 22 | 23 | 24 | io.quarkus 25 | quarkus-resteasy 26 | 27 | 28 | io.quarkus 29 | quarkus-resteasy-jackson 30 | 31 | 32 | io.quarkiverse.mybatis 33 | quarkus-mybatis 34 | ${project.version} 35 | 36 | 37 | io.quarkus 38 | quarkus-jdbc-h2 39 | 40 | 41 | io.quarkus 42 | quarkus-jdbc-derby 43 | 44 | 45 | 46 | 47 | io.quarkus 48 | quarkus-junit5 49 | test 50 | 51 | 52 | io.rest-assured 53 | rest-assured 54 | test 55 | 56 | 57 | io.quarkus 58 | quarkus-test-h2 59 | test 60 | 61 | io.quarkus 62 | quarkus-test-derby 63 | test 64 | 65 | 66 | 67 | 68 | 69 | 70 | io.quarkus 71 | quarkus-maven-plugin 72 | ${quarkus.version} 73 | 74 | true 75 | ${quarkus.build.skip} 76 | 77 | 78 | 79 | 80 | build 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | native-image 91 | 92 | 93 | native 94 | 95 | 96 | 97 | native 98 | 99 | 100 | 101 | 102 | org.apache.maven.plugins 103 | maven-failsafe-plugin 104 | 105 | 106 | 107 | integration-test 108 | verify 109 | 110 | 111 | 112 | ${project.build.directory}/${project.build.finalName}-runner 113 | org.jboss.logmanager.LogManager 114 | ${maven.home} 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/Book.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Book implements Serializable { 6 | private Integer id; 7 | private User author; 8 | private String title; 9 | 10 | public Integer getId() { 11 | return id; 12 | } 13 | 14 | public void setId(Integer id) { 15 | this.id = id; 16 | } 17 | 18 | public User getAuthor() { 19 | return author; 20 | } 21 | 22 | public void setAuthor(User author) { 23 | this.author = author; 24 | } 25 | 26 | public String getTitle() { 27 | return title; 28 | } 29 | 30 | public void setTitle(String title) { 31 | this.title = title; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/BookMapper.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import org.apache.ibatis.annotations.CacheNamespace; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.One; 6 | import org.apache.ibatis.annotations.Result; 7 | import org.apache.ibatis.annotations.Results; 8 | import org.apache.ibatis.annotations.Select; 9 | 10 | @Mapper 11 | @CacheNamespace 12 | public interface BookMapper { 13 | @Select("SELECT id, author_id, title from books where id = #{id}") 14 | @Results(value = { 15 | @Result(property = "id", column = "id"), 16 | @Result(property = "author", column = "author_id", javaType = User.class, one = @One(select = "getUser")) 17 | }) 18 | Book getBook(Integer id); 19 | 20 | @Select("select * from users where id = #{id}") 21 | User getUser(Integer id); 22 | 23 | Book findById(Integer id); 24 | } 25 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/DerbyUserMapper.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.apache.ibatis.annotations.Select; 5 | 6 | import io.quarkiverse.mybatis.runtime.meta.MapperDataSource; 7 | 8 | @Mapper 9 | @MapperDataSource("derby") 10 | public interface DerbyUserMapper { 11 | @Select("select count(*) from users") 12 | int getUserCount(); 13 | 14 | User findById(Integer id); 15 | } 16 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/MyBatisResource.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | import jakarta.inject.Inject; 8 | import jakarta.transaction.Transactional; 9 | import jakarta.ws.rs.Consumes; 10 | import jakarta.ws.rs.DELETE; 11 | import jakarta.ws.rs.FormParam; 12 | import jakarta.ws.rs.GET; 13 | import jakarta.ws.rs.POST; 14 | import jakarta.ws.rs.Path; 15 | import jakarta.ws.rs.PathParam; 16 | import jakarta.ws.rs.Produces; 17 | import jakarta.ws.rs.core.MediaType; 18 | 19 | import org.apache.ibatis.cursor.Cursor; 20 | 21 | @Path("/mybatis") 22 | public class MyBatisResource { 23 | 24 | @Inject 25 | UserMapper userMapper; 26 | 27 | @Inject 28 | BookMapper bookMapper; 29 | 30 | @Inject 31 | DerbyUserMapper derbyUserMapper; 32 | 33 | @Path("/user/{id}") 34 | @GET 35 | @Produces(MediaType.APPLICATION_JSON) 36 | @Transactional 37 | public User getUser(@PathParam("id") Integer id) { 38 | return userMapper.getUser(id); 39 | } 40 | 41 | @Path("/user/dynamic/{id}") 42 | @GET 43 | @Produces(MediaType.APPLICATION_JSON) 44 | public User getDynamicUser(@PathParam("id") Integer id) { 45 | return userMapper.selectOne(id); 46 | } 47 | 48 | @Path("/user") 49 | @POST 50 | @Produces(MediaType.TEXT_PLAIN) 51 | @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 52 | public Integer createUser(@FormParam("id") Integer id, @FormParam("name") String name, 53 | @FormParam("externalId") UUID externalId) { 54 | return userMapper.createUser(id, name, externalId); 55 | } 56 | 57 | @Path("/user/{id}") 58 | @DELETE 59 | @Produces(MediaType.TEXT_PLAIN) 60 | public Integer removeUser(@PathParam("id") Integer id) { 61 | return userMapper.removeUser(id); 62 | } 63 | 64 | @Path("/user/count/h2") 65 | @GET 66 | @Produces(MediaType.APPLICATION_JSON) 67 | public int getUserCount() { 68 | return userMapper.getUserCount(); 69 | } 70 | 71 | @Path("/user/count/derby") 72 | @GET 73 | @Produces(MediaType.APPLICATION_JSON) 74 | public int getDerbyUserCount() { 75 | return derbyUserMapper.getUserCount(); 76 | } 77 | 78 | @Path("/user/cursor") 79 | @GET 80 | @Produces(MediaType.APPLICATION_JSON) 81 | @Transactional 82 | public List getUserCursor() throws Exception { 83 | List result = new ArrayList<>(); 84 | try (Cursor cursor = userMapper.selectCursor()) { 85 | for (String name : cursor) { 86 | result.add(name); 87 | } 88 | } 89 | return result; 90 | } 91 | 92 | @Path("/book/{id}") 93 | @GET 94 | @Produces(MediaType.APPLICATION_JSON) 95 | public Book getBook(@PathParam("id") Integer id) { 96 | return bookMapper.getBook(id); 97 | } 98 | 99 | @Path("/book/xmlMapper/{id}") 100 | @GET 101 | @Produces(MediaType.APPLICATION_JSON) 102 | public Book findBookById(@PathParam("id") Integer id) { 103 | return bookMapper.findById(id); 104 | } 105 | 106 | @Path("/user/xmlMapper/{id}") 107 | @GET 108 | @Produces(MediaType.APPLICATION_JSON) 109 | public User findUserById(@PathParam("id") Integer id) { 110 | return userMapper.findById(id); 111 | } 112 | 113 | @Path("/user/xmlMapper/derby/{id}") 114 | @GET 115 | @Produces(MediaType.APPLICATION_JSON) 116 | public User findDerbyUserById(@PathParam("id") Integer id) { 117 | return derbyUserMapper.findById(id); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/PageConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import org.apache.ibatis.plugin.Interceptor; 4 | import org.apache.ibatis.plugin.Invocation; 5 | import org.apache.ibatis.session.Configuration; 6 | 7 | public class PageConfigurationFactory { 8 | public Configuration getConfiguration() { 9 | Configuration configuration = new Configuration(); 10 | configuration.addInterceptor(new PageInterceptor()); 11 | return configuration; 12 | } 13 | } 14 | 15 | class PageInterceptor implements Interceptor { 16 | 17 | @Override 18 | public Object intercept(Invocation invocation) throws Throwable { 19 | return invocation.proceed(); 20 | } 21 | } -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/SqlProviderAdapter.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | public class SqlProviderAdapter { 4 | public static String select() { 5 | return "select * from users where id = #{id}"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/User.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | public class User implements Serializable { 7 | private Integer id; 8 | private String name; 9 | private UUID externalId; 10 | 11 | public Integer getId() { 12 | return id; 13 | } 14 | 15 | public void setId(Integer id) { 16 | this.id = id; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public UUID getExternalId() { 28 | return externalId; 29 | } 30 | 31 | public void setExternalId(UUID externalId) { 32 | this.externalId = externalId; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/UserMapper.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import java.util.UUID; 4 | 5 | import org.apache.ibatis.annotations.CacheNamespace; 6 | import org.apache.ibatis.annotations.Delete; 7 | import org.apache.ibatis.annotations.Insert; 8 | import org.apache.ibatis.annotations.Mapper; 9 | import org.apache.ibatis.annotations.Param; 10 | import org.apache.ibatis.annotations.Select; 11 | import org.apache.ibatis.annotations.SelectProvider; 12 | import org.apache.ibatis.cursor.Cursor; 13 | 14 | @Mapper 15 | @CacheNamespace(readWrite = false) 16 | public interface UserMapper { 17 | 18 | @Select("select * from users where id = #{id}") 19 | User getUser(Integer id); 20 | 21 | @Insert("insert into users (id, name, externalId) values (#{id}, #{name}, #{externalId,jdbcType=OTHER})") 22 | Integer createUser(@Param("id") Integer id, @Param("name") String name, @Param("externalId") UUID externalId); 23 | 24 | @Delete("delete from users where id = #{id}") 25 | Integer removeUser(Integer id); 26 | 27 | @SelectProvider(type = SqlProviderAdapter.class, method = "select") 28 | User selectOne(Integer id); 29 | 30 | @Select("select count(*) from users") 31 | int getUserCount(); 32 | 33 | @Select("select name from users") 34 | Cursor selectCursor(); 35 | 36 | User findById(Integer id); 37 | } 38 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/UuidJdbcTypeHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import java.sql.*; 4 | import java.util.UUID; 5 | 6 | import org.apache.ibatis.type.BaseTypeHandler; 7 | import org.apache.ibatis.type.JdbcType; 8 | import org.apache.ibatis.type.MappedJdbcTypes; 9 | 10 | @MappedJdbcTypes(value = JdbcType.OTHER, includeNullJdbcType = true) 11 | public class UuidJdbcTypeHandler extends BaseTypeHandler { 12 | 13 | public static UUID fromStringAllowNulls(String uuid) { 14 | if (uuid == null || uuid.trim().equals("")) { 15 | return null; 16 | } else { 17 | return UUID.fromString(uuid); 18 | } 19 | } 20 | 21 | @Override 22 | public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException { 23 | // note the difference in how H2 wants to persist a UUID 24 | ps.setObject(i, parameter); 25 | } 26 | 27 | @Override 28 | public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 29 | return fromStringAllowNulls(rs.getString(columnName)); 30 | } 31 | 32 | @Override 33 | public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 34 | return fromStringAllowNulls(rs.getString(columnIndex)); 35 | } 36 | 37 | @Override 38 | public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 39 | return fromStringAllowNulls(cs.getString(columnIndex)); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/java/io/quarkiverse/it/mybatis/UuidTypeHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import java.sql.*; 4 | import java.util.UUID; 5 | 6 | import org.apache.ibatis.type.BaseTypeHandler; 7 | import org.apache.ibatis.type.JdbcType; 8 | import org.apache.ibatis.type.MappedTypes; 9 | 10 | @MappedTypes(UUID.class) 11 | public class UuidTypeHandler extends BaseTypeHandler { 12 | 13 | public static UUID fromStringAllowNulls(String uuid) { 14 | if (uuid == null || uuid.trim().equals("")) { 15 | return null; 16 | } else { 17 | return UUID.fromString(uuid); 18 | } 19 | } 20 | 21 | @Override 22 | public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) throws SQLException { 23 | // note the difference in how H2 wants to persist a UUID 24 | ps.setObject(i, parameter); 25 | } 26 | 27 | @Override 28 | public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException { 29 | return fromStringAllowNulls(rs.getString(columnName)); 30 | } 31 | 32 | @Override 33 | public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 34 | return fromStringAllowNulls(rs.getString(columnIndex)); 35 | } 36 | 37 | @Override 38 | public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 39 | return fromStringAllowNulls(cs.getString(columnIndex)); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/application-xml.properties: -------------------------------------------------------------------------------- 1 | quarkus.mybatis.xmlconfig.enable=true 2 | quarkus.mybatis.environment=development 3 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # H2 2 | quarkus.datasource.db-kind=h2 3 | quarkus.datasource.username=username-default 4 | quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:default 5 | quarkus.mybatis.initial-sql=insert.sql 6 | quarkus.mybatis.configuration-factory=io.quarkiverse.it.mybatis.PageConfigurationFactory 7 | 8 | # Derby 9 | quarkus.datasource.derby.db-kind=derby 10 | quarkus.datasource.derby.jdbc.url=jdbc:derby://localhost:1527/memory:testDB;create=true 11 | quarkus.mybatis.derby.initial-sql=insert-derby.sql 12 | 13 | quarkus.mybatis.mapper-locations=mapper,otherMapper/ 14 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/insert-derby.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE USERS ( 2 | id integer not null primary key, 3 | name varchar(80) not null, 4 | external_id varchar(50) not null 5 | ); 6 | 7 | DELETE FROM users; 8 | insert into users (id, name, external_id) values (1, 'Test User1', 'ccb16b65-8924-4c3f-8c55-681d85a16e79'); 9 | insert into users (id, name, external_id) values (2, 'Test User2', 'ae43f233-0b69-4c4e-bfa9-656c475150ad'); 10 | insert into users (id, name, external_id) values (3, 'Test User3', '5640e179-466c-427e-9747-4cfac09a2f9a'); 11 | insert into users (id, name, external_id) values (4, 'Test User4', '5640e179-466c-427e-9747-4cfacsfdsdfd'); 12 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/insert.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE USERS IF EXISTS; 2 | DROP TABLE BOOKS IF EXISTS; 3 | 4 | CREATE TABLE USERS ( 5 | id integer not null primary key, 6 | name varchar(80) not null, 7 | externalId uuid not null 8 | ); 9 | 10 | CREATE TABLE BOOKS ( 11 | id integer not null primary key, 12 | title varchar(80) not null, 13 | author_id integer not null, 14 | 15 | foreign key(author_id) references USERS(id) 16 | ); 17 | 18 | DELETE FROM users; 19 | insert into users (id, name, externalId) values (1, 'Test User1', 'ccb16b65-8924-4c3f-8c55-681d85a16e79'); 20 | insert into users (id, name, externalId) values (2, 'Test User2', 'ae43f233-0b69-4c4e-bfa9-656c475150ad'); 21 | insert into users (id, name, externalId) values (3, 'Test User3', '5640e179-466c-427e-9747-4cfac09a2f9a'); 22 | 23 | DELETE from books; 24 | insert into books(id, title, author_id) values (1, 'Test Title', 1); 25 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/mapper/DerbyUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/main/resources/otherMapper/BookMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/BaseMyBatisTestCase.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import static org.hamcrest.core.Is.is; 4 | 5 | import java.util.UUID; 6 | 7 | import io.restassured.RestAssured; 8 | 9 | public class BaseMyBatisTestCase { 10 | 11 | public void runTest() { 12 | RestAssured.when().get("/mybatis/user/1").then() 13 | .body(is("{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"}")); 14 | 15 | RestAssured.when().get("/mybatis/user/dynamic/1").then() 16 | .body(is("{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"}")); 17 | 18 | RestAssured.given().param("id", "5") 19 | .param("name", "New User") 20 | .param("externalId", UUID.fromString("9b036c98-eb1d-4580-a8bb-1115d7a3cd44")) 21 | .post("/mybatis/user") 22 | .then().body(is("1")); 23 | 24 | RestAssured.when().delete("/mybatis/user/3").then() 25 | .body(is("1")); 26 | 27 | RestAssured.when().get("/mybatis/book/1").then() 28 | .body(is( 29 | "{\"id\":1,\"author\":{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"},\"title\":\"Test Title\"}")); 30 | 31 | RestAssured.when().get("/mybatis/book/xmlMapper/1").then() 32 | .body(is( 33 | "{\"id\":1,\"author\":{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"},\"title\":\"Test Title\"}")); 34 | 35 | RestAssured.when().get("/mybatis/user/xmlMapper/1").then() 36 | .body(is("{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"}")); 37 | 38 | RestAssured.when().get("/mybatis/user/xmlMapper/derby/1").then() 39 | .body(is("{\"id\":1,\"name\":\"Test User1\",\"externalId\":\"ccb16b65-8924-4c3f-8c55-681d85a16e79\"}")); 40 | 41 | RestAssured.when().get("/mybatis/user/cursor").then() 42 | .body(is("[\"Test User1\",\"Test User2\",\"New User\"]")); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/MultipleDataSourcesTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import static org.hamcrest.core.Is.is; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | import io.quarkus.test.junit.QuarkusTest; 8 | import io.restassured.RestAssured; 9 | 10 | @QuarkusTest 11 | class MultipleDataSourcesTest { 12 | @Test 13 | public void test() { 14 | RestAssured.when().get("/mybatis/user/count/h2").then() 15 | .body(is("3")); 16 | 17 | RestAssured.when().get("/mybatis/user/count/derby").then() 18 | .body(is("4")); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/MyBatisIT.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import io.quarkus.test.junit.QuarkusIntegrationTest; 4 | 5 | @QuarkusIntegrationTest 6 | class MyBatisIT extends MyBatisTest { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/MyBatisTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import io.quarkus.test.junit.QuarkusTest; 6 | 7 | @QuarkusTest 8 | class MyBatisTest extends BaseMyBatisTestCase { 9 | 10 | @Test 11 | void test() { 12 | runTest(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/MyBatisXmlConfigIT.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import io.quarkus.test.junit.QuarkusIntegrationTest; 4 | 5 | @QuarkusIntegrationTest 6 | public class MyBatisXmlConfigIT extends MyBatisXmlConfigTest { 7 | } 8 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/MyBatisXmlConfigTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import io.quarkus.test.junit.QuarkusTest; 6 | import io.quarkus.test.junit.TestProfile; 7 | 8 | @QuarkusTest 9 | @TestProfile(XmlConfigProfile.class) 10 | public class MyBatisXmlConfigTest extends BaseMyBatisTestCase { 11 | 12 | @Test 13 | void test() { 14 | runTest(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/TestResources.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import io.quarkus.test.common.QuarkusTestResource; 4 | import io.quarkus.test.derby.DerbyDatabaseTestResource; 5 | import io.quarkus.test.h2.H2DatabaseTestResource; 6 | 7 | @QuarkusTestResource(H2DatabaseTestResource.class) 8 | @QuarkusTestResource(DerbyDatabaseTestResource.class) 9 | public class TestResources { 10 | } 11 | -------------------------------------------------------------------------------- /mybatis/integration-tests/src/test/java/io/quarkiverse/it/mybatis/XmlConfigProfile.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.it.mybatis; 2 | 3 | import io.quarkus.test.junit.QuarkusTestProfile; 4 | 5 | public class XmlConfigProfile implements QuarkusTestProfile { 6 | @Override 7 | public String getConfigProfile() { 8 | return "xml"; 9 | } 10 | } -------------------------------------------------------------------------------- /mybatis/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.quarkiverse.mybatis 7 | quarkus-parent 8 | 999-SNAPSHOT 9 | 10 | 11 | quarkus-mybatis-parent 12 | Quarkus - Mybatis - Parent 13 | pom 14 | 15 | 16 | deployment 17 | runtime 18 | docs 19 | 20 | 21 | 22 | 23 | it 24 | 25 | 26 | performRelease 27 | !true 28 | 29 | 30 | 31 | integration-tests 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /mybatis/runtime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | io.quarkiverse.mybatis 5 | quarkus-mybatis-parent 6 | 999-SNAPSHOT 7 | ../ 8 | 9 | 4.0.0 10 | 11 | quarkus-mybatis 12 | Quarkus - Mybatis - Runtime 13 | MyBatis SQL mapper framework for Java 14 | 15 | 16 | 17 | io.quarkus 18 | quarkus-arc 19 | 20 | 21 | io.quarkus 22 | quarkus-agroal 23 | 24 | 25 | org.mybatis 26 | mybatis 27 | 28 | 29 | org.graalvm.sdk 30 | nativeimage 31 | 32 | 33 | 34 | 35 | 36 | 37 | io.quarkus 38 | quarkus-extension-maven-plugin 39 | ${quarkus.version} 40 | 41 | 42 | 43 | extension-descriptor 44 | 45 | compile 46 | 47 | ${project.groupId}:${project.artifactId}-deployment:${project.version} 48 | 49 | 50 | 51 | 52 | 53 | 54 | maven-compiler-plugin 55 | 56 | 57 | 58 | io.quarkus 59 | quarkus-extension-processor 60 | ${quarkus.version} 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/ConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import org.apache.ibatis.session.Configuration; 4 | 5 | public interface ConfigurationFactory { 6 | Configuration createConfiguration(); 7 | 8 | default boolean isOverrideSetting() { 9 | return false; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/MyBatisConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import org.apache.ibatis.session.Configuration; 4 | 5 | public class MyBatisConfigurationFactory implements ConfigurationFactory { 6 | @Override 7 | public Configuration createConfiguration() { 8 | return new Configuration(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/MyBatisXMLConfigDelegateBuilder.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import java.io.Reader; 4 | 5 | import org.apache.ibatis.builder.xml.XMLConfigBuilder; 6 | import org.apache.ibatis.io.Resources; 7 | import org.apache.ibatis.session.Configuration; 8 | 9 | import io.quarkiverse.mybatis.runtime.config.MyBatisRuntimeConfig; 10 | 11 | public class MyBatisXMLConfigDelegateBuilder implements XMLConfigDelegateBuilder { 12 | private XMLConfigBuilder builder; 13 | private MyBatisRuntimeConfig config; 14 | 15 | public MyBatisXMLConfigDelegateBuilder() { 16 | 17 | } 18 | 19 | @Override 20 | public void setConfig(MyBatisRuntimeConfig config) { 21 | this.config = config; 22 | } 23 | 24 | @Override 25 | public Configuration getConfiguration() throws Exception { 26 | return getBuilder().getConfiguration(); 27 | } 28 | 29 | @Override 30 | public Configuration parse() throws Exception { 31 | return getBuilder().parse(); 32 | } 33 | 34 | private XMLConfigBuilder getBuilder() throws Exception { 35 | if (builder == null) { 36 | Reader reader = Resources.getResourceAsReader(config.xmlconfig().path()); 37 | builder = new XMLConfigBuilder(reader, config.environment()); 38 | } 39 | return builder; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/QuarkusDataSourceFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import java.util.Properties; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.apache.ibatis.datasource.DataSourceFactory; 8 | 9 | public class QuarkusDataSourceFactory implements DataSourceFactory { 10 | private Properties properties; 11 | private QuarkusDataSource dataSource; 12 | 13 | public QuarkusDataSourceFactory() { 14 | } 15 | 16 | @Override 17 | public void setProperties(Properties properties) { 18 | this.properties = properties; 19 | if (dataSource == null) { 20 | dataSource = new QuarkusDataSource(properties.getProperty("db", "")); 21 | } 22 | } 23 | 24 | @Override 25 | public DataSource getDataSource() { 26 | return dataSource; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/QuarkusDatabaseIdProvider.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import java.sql.SQLException; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.apache.ibatis.mapping.DatabaseIdProvider; 8 | import org.eclipse.microprofile.config.ConfigProvider; 9 | 10 | public class QuarkusDatabaseIdProvider implements DatabaseIdProvider { 11 | @Override 12 | public String getDatabaseId(final DataSource dataSource) throws SQLException { 13 | if (dataSource instanceof QuarkusDataSource ds) { 14 | String name = ds.getDataSourceName(); 15 | return ConfigProvider.getConfig().getOptionalValue( 16 | "quarkus.mybatis." + ("".equals(name) ? "" : name + ".") + "database-id", String.class) 17 | .orElse(null); 18 | } 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/TransactionalSqlSession.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import static java.lang.reflect.Proxy.newProxyInstance; 4 | 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | import java.sql.Connection; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | import jakarta.transaction.Status; 13 | import jakarta.transaction.Synchronization; 14 | import jakarta.transaction.Transaction; 15 | import jakarta.transaction.TransactionManager; 16 | 17 | import org.apache.ibatis.cursor.Cursor; 18 | import org.apache.ibatis.executor.BatchResult; 19 | import org.apache.ibatis.reflection.ExceptionUtil; 20 | import org.apache.ibatis.session.Configuration; 21 | import org.apache.ibatis.session.ResultHandler; 22 | import org.apache.ibatis.session.RowBounds; 23 | import org.apache.ibatis.session.SqlSession; 24 | import org.apache.ibatis.session.SqlSessionFactory; 25 | 26 | public class TransactionalSqlSession implements SqlSession { 27 | private final SqlSessionFactory sqlSessionFactory; 28 | private final TransactionManager transactionManager; 29 | 30 | private final SqlSession sqlSessionProxy; 31 | 32 | public TransactionalSqlSession(SqlSessionFactory sqlSessionFactory, TransactionManager transactionManager) { 33 | this.sqlSessionFactory = sqlSessionFactory; 34 | this.transactionManager = transactionManager; 35 | this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSession.class.getClassLoader(), 36 | new Class[] { SqlSession.class }, new TransactionalSqlSessionInterceptor()); 37 | } 38 | 39 | @Override 40 | public T selectOne(String statement) { 41 | return this.sqlSessionProxy.selectOne(statement); 42 | } 43 | 44 | @Override 45 | public T selectOne(String statement, Object parameter) { 46 | return this.sqlSessionProxy.selectOne(statement, parameter); 47 | } 48 | 49 | @Override 50 | public List selectList(String statement) { 51 | return this.sqlSessionProxy.selectList(statement); 52 | } 53 | 54 | @Override 55 | public List selectList(String statement, Object parameter) { 56 | return this.sqlSessionProxy.selectList(statement, parameter); 57 | } 58 | 59 | @Override 60 | public List selectList(String statement, Object parameter, RowBounds rowBounds) { 61 | return this.sqlSessionProxy.selectList(statement, parameter, rowBounds); 62 | } 63 | 64 | @Override 65 | public Map selectMap(String statement, String mapKey) { 66 | return this.sqlSessionProxy.selectMap(statement, mapKey); 67 | } 68 | 69 | @Override 70 | public Map selectMap(String statement, Object parameter, String mapKey) { 71 | return this.sqlSessionProxy.selectMap(statement, parameter, mapKey); 72 | } 73 | 74 | @Override 75 | public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { 76 | return this.sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds); 77 | } 78 | 79 | @Override 80 | public Cursor selectCursor(String statement) { 81 | return this.sqlSessionProxy.selectCursor(statement); 82 | } 83 | 84 | @Override 85 | public Cursor selectCursor(String statement, Object parameter) { 86 | return this.sqlSessionProxy.selectCursor(statement, parameter); 87 | } 88 | 89 | @Override 90 | public Cursor selectCursor(String statement, Object parameter, RowBounds rowBounds) { 91 | return this.sqlSessionProxy.selectCursor(statement, parameter, rowBounds); 92 | } 93 | 94 | @Override 95 | public void select(String statement, Object parameter, ResultHandler handler) { 96 | this.sqlSessionProxy.select(statement, parameter, handler); 97 | } 98 | 99 | @Override 100 | public void select(String statement, ResultHandler handler) { 101 | this.sqlSessionProxy.select(statement, handler); 102 | } 103 | 104 | @Override 105 | public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { 106 | this.sqlSessionProxy.select(statement, parameter, rowBounds, handler); 107 | } 108 | 109 | @Override 110 | public int insert(String statement) { 111 | return this.sqlSessionProxy.insert(statement); 112 | } 113 | 114 | @Override 115 | public int insert(String statement, Object parameter) { 116 | return this.sqlSessionProxy.insert(statement, parameter); 117 | } 118 | 119 | @Override 120 | public int update(String statement) { 121 | return this.sqlSessionProxy.update(statement); 122 | } 123 | 124 | @Override 125 | public int update(String statement, Object parameter) { 126 | return this.sqlSessionProxy.update(statement, parameter); 127 | } 128 | 129 | @Override 130 | public int delete(String statement) { 131 | return this.sqlSessionProxy.delete(statement); 132 | } 133 | 134 | @Override 135 | public int delete(String statement, Object parameter) { 136 | return this.sqlSessionProxy.delete(statement, parameter); 137 | } 138 | 139 | @Override 140 | public void commit() { 141 | throw new UnsupportedOperationException("Manual close is not allowed over a Transactional SqlSession"); 142 | } 143 | 144 | @Override 145 | public void commit(boolean force) { 146 | throw new UnsupportedOperationException("Manual close is not allowed over a Transactional SqlSession"); 147 | } 148 | 149 | @Override 150 | public void rollback() { 151 | throw new UnsupportedOperationException("Manual close is not allowed over a Transactional SqlSession"); 152 | } 153 | 154 | @Override 155 | public void rollback(boolean force) { 156 | throw new UnsupportedOperationException("Manual close is not allowed over a Transactional SqlSession"); 157 | } 158 | 159 | @Override 160 | public List flushStatements() { 161 | return this.sqlSessionProxy.flushStatements(); 162 | } 163 | 164 | @Override 165 | public void close() { 166 | throw new UnsupportedOperationException("Manual close is not allowed over a Transactional SqlSession"); 167 | } 168 | 169 | @Override 170 | public void clearCache() { 171 | this.sqlSessionProxy.clearCache(); 172 | } 173 | 174 | @Override 175 | public Configuration getConfiguration() { 176 | return this.sqlSessionFactory.getConfiguration(); 177 | } 178 | 179 | @Override 180 | public T getMapper(Class type) { 181 | return getConfiguration().getMapper(type, this); 182 | } 183 | 184 | @Override 185 | public Connection getConnection() { 186 | return this.sqlSessionProxy.getConnection(); 187 | } 188 | 189 | private class TransactionalSqlSessionInterceptor implements InvocationHandler { 190 | private final Map sqlSessionMap = new ConcurrentHashMap<>(); 191 | 192 | @Override 193 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 194 | SqlSession sqlSession = null; 195 | try { 196 | sqlSession = getSqlSession(); 197 | Object result = method.invoke(sqlSession, args); 198 | sqlSession.commit(); 199 | return result; 200 | } catch (Throwable t) { 201 | sqlSession.rollback(); 202 | throw ExceptionUtil.unwrapThrowable(t); 203 | } finally { 204 | if (!isTransactionActive() && sqlSession != null) { 205 | sqlSession.close(); 206 | } 207 | } 208 | } 209 | 210 | private SqlSession getSqlSession() throws Exception { 211 | if (isTransactionActive()) { 212 | SqlSession sqlSession = sqlSessionMap.computeIfAbsent(transactionManager.getTransaction(), 213 | (transaction) -> { 214 | SqlSession session = sqlSessionFactory.openSession(); 215 | try { 216 | transaction.registerSynchronization(new Synchronization() { 217 | @Override 218 | public void beforeCompletion() { 219 | session.close(); 220 | sqlSessionMap.remove(transaction); 221 | } 222 | 223 | @Override 224 | public void afterCompletion(int status) { 225 | } 226 | }); 227 | } catch (Exception e) { 228 | throw new RuntimeException( 229 | "Session " + session + " can not register synchronization in transaction ", e); 230 | } 231 | return session; 232 | }); 233 | return sqlSession; 234 | } else { 235 | return sqlSessionFactory.openSession(); 236 | } 237 | } 238 | 239 | private boolean isTransactionActive() { 240 | try { 241 | if (transactionManager == null) { 242 | return false; 243 | } 244 | Transaction tx = transactionManager.getTransaction(); 245 | return tx != null 246 | && (tx.getStatus() == Status.STATUS_ACTIVE || tx.getStatus() == Status.STATUS_MARKED_ROLLBACK); 247 | } catch (Exception e) { 248 | return false; 249 | } 250 | } 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/XMLConfigDelegateBuilder.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime; 2 | 3 | import org.apache.ibatis.session.Configuration; 4 | 5 | import io.quarkiverse.mybatis.runtime.config.MyBatisRuntimeConfig; 6 | 7 | public interface XMLConfigDelegateBuilder { 8 | void setConfig(MyBatisRuntimeConfig config); 9 | 10 | Configuration getConfiguration() throws Exception; 11 | 12 | Configuration parse() throws Exception; 13 | } 14 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/config/MyBatisDataSourceRuntimeConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime.config; 2 | 3 | import java.util.Optional; 4 | import java.util.Set; 5 | 6 | import org.apache.ibatis.mapping.ResultSetType; 7 | import org.apache.ibatis.session.AutoMappingBehavior; 8 | import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior; 9 | import org.apache.ibatis.session.ExecutorType; 10 | import org.apache.ibatis.session.LocalCacheScope; 11 | import org.apache.ibatis.type.JdbcType; 12 | 13 | import io.quarkus.runtime.annotations.ConfigGroup; 14 | import io.smallrye.config.WithName; 15 | 16 | @ConfigGroup 17 | public interface MyBatisDataSourceRuntimeConfig { 18 | /** 19 | * MyBatis environment id 20 | */ 21 | Optional environment(); 22 | 23 | /** 24 | * MyBatis transaction factory 25 | */ 26 | Optional transactionFactory(); 27 | 28 | /** 29 | * MyBatis databaseId 30 | */ 31 | Optional databaseId(); 32 | 33 | /** 34 | * MyBatis initial sql 35 | */ 36 | @WithName("initial-sql") 37 | Optional initialSql(); 38 | 39 | /** 40 | * MyBatis cacheEnabled 41 | */ 42 | Optional cacheEnabled(); 43 | 44 | /** 45 | * MyBatis lazyLoadingEnabled 46 | */ 47 | Optional lazyLoadingEnabled(); 48 | 49 | /** 50 | * MyBatis aggressiveLazyLoading 51 | */ 52 | Optional aggressiveLazyLoading(); 53 | 54 | /** 55 | * MyBatis useColumnLabel 56 | */ 57 | Optional useColumnLabel(); 58 | 59 | /** 60 | * MyBatis useGeneratedKeys 61 | */ 62 | Optional useGeneratedKeys(); 63 | 64 | /** 65 | * MyBatis autoMappingBehavior 66 | */ 67 | Optional autoMappingBehavior(); 68 | 69 | /** 70 | * MyBatis autoMappingUnknownColumnBehavior 71 | */ 72 | Optional autoMappingUnknownColumnBehavior(); 73 | 74 | /** 75 | * MyBatis defaultExecutorType 76 | */ 77 | Optional defaultExecutorType(); 78 | 79 | /** 80 | * MyBatis defaultStatementTimeout 81 | */ 82 | Optional defaultStatementTimeout(); 83 | 84 | /** 85 | * MyBatis defaultFetchSize 86 | */ 87 | Optional defaultFetchSize(); 88 | 89 | /** 90 | * MyBatis defaultResultSetType 91 | */ 92 | Optional defaultResultSetType(); 93 | 94 | /** 95 | * MyBatis safeRowBoundsEnabled 96 | */ 97 | Optional safeRowBoundsEnabled(); 98 | 99 | /** 100 | * MyBatis safeResultHandlerEnabled 101 | */ 102 | Optional safeResultHandlerEnabled(); 103 | 104 | /** 105 | * MyBatis mapUnderscoreToCamelCase 106 | */ 107 | Optional mapUnderscoreToCamelCase(); 108 | 109 | /** 110 | * MyBatis multipleResultSetsEnabled 111 | */ 112 | Optional multipleResultSetsEnabled(); 113 | 114 | /** 115 | * MyBatis localCacheScope 116 | */ 117 | Optional localCacheScope(); 118 | 119 | /** 120 | * MyBatis jdbcTypeForNull 121 | */ 122 | Optional jdbcTypeForNull(); 123 | 124 | /** 125 | * MyBatis lazyLoadTriggerMethods 126 | */ 127 | Optional> lazyLoadTriggerMethods(); 128 | 129 | /** 130 | * MyBatis defaultScriptingLanguage 131 | */ 132 | Optional defaultScriptingLanguage(); 133 | 134 | /** 135 | * MyBatis defaultEnumTypeHandler 136 | */ 137 | Optional defaultEnumTypeHandler(); 138 | 139 | /** 140 | * MyBatis callSettersOnNulls 141 | */ 142 | Optional callSettersOnNulls(); 143 | 144 | /** 145 | * MyBatis returnInstanceForEmptyRow 146 | */ 147 | Optional returnInstanceForEmptyRow(); 148 | 149 | /** 150 | * MyBatis logPrefix 151 | */ 152 | Optional logPrefix(); 153 | 154 | /** 155 | * MyBatis logImpl 156 | */ 157 | Optional logImpl(); 158 | 159 | /** 160 | * MyBatis proxyFactory 161 | */ 162 | Optional proxyFactory(); 163 | 164 | /** 165 | * MyBatis vfsImpl 166 | */ 167 | Optional vfsImpl(); 168 | 169 | /** 170 | * MyBatis useActualParamName 171 | */ 172 | Optional useActualParamName(); 173 | 174 | /** 175 | * MyBatis configurationFactory 176 | */ 177 | Optional configurationFactory(); 178 | 179 | /** 180 | * MyBatis shrinkWhitespacesInSql 181 | */ 182 | Optional shrinkWhitespacesInSql(); 183 | 184 | /** 185 | * MyBatis defaultSqlProviderType 186 | */ 187 | Optional defaultSqlProviderType(); 188 | } 189 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/config/MyBatisRuntimeConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime.config; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | import java.util.Set; 7 | 8 | import org.apache.ibatis.mapping.ResultSetType; 9 | import org.apache.ibatis.session.AutoMappingBehavior; 10 | import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior; 11 | import org.apache.ibatis.session.ExecutorType; 12 | import org.apache.ibatis.session.LocalCacheScope; 13 | import org.apache.ibatis.type.JdbcType; 14 | 15 | import io.quarkus.runtime.annotations.ConfigDocMapKey; 16 | import io.quarkus.runtime.annotations.ConfigDocSection; 17 | import io.quarkus.runtime.annotations.ConfigGroup; 18 | import io.quarkus.runtime.annotations.ConfigPhase; 19 | import io.quarkus.runtime.annotations.ConfigRoot; 20 | import io.smallrye.config.ConfigMapping; 21 | import io.smallrye.config.WithDefault; 22 | import io.smallrye.config.WithName; 23 | import io.smallrye.config.WithParentName; 24 | 25 | @ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) 26 | @ConfigMapping(prefix = "quarkus.mybatis") 27 | public interface MyBatisRuntimeConfig { 28 | /** 29 | * Data sources config 30 | */ 31 | @ConfigDocSection 32 | @ConfigDocMapKey("data-source-name") 33 | @WithParentName 34 | Map dataSources(); 35 | 36 | /** 37 | * Support XML Configuration 38 | */ 39 | XmlConfig xmlconfig(); 40 | 41 | @ConfigGroup 42 | public interface XmlConfig { 43 | /** 44 | * enable mybatis xml configuration 45 | */ 46 | @WithDefault("false") 47 | boolean enable(); 48 | 49 | /** 50 | * xml configuration file 51 | */ 52 | @WithDefault("mybatis-config.xml") 53 | String path(); 54 | } 55 | 56 | /** 57 | * MyBatis environment id 58 | */ 59 | @WithDefault("quarkus") 60 | String environment(); 61 | 62 | /** 63 | * MyBatis transaction factory 64 | */ 65 | @WithDefault("MANAGED") 66 | String transactionFactory(); 67 | 68 | /** 69 | * MyBatis data source 70 | */ 71 | @WithName("datasource") 72 | Optional dataSource(); 73 | 74 | /** 75 | * MyBatis DatabaseId 76 | */ 77 | Optional databaseId(); 78 | 79 | /** 80 | * MyBatis initial sql 81 | */ 82 | @WithName("initial-sql") 83 | Optional initialSql(); 84 | 85 | /** 86 | * MyBatis cacheEnabled 87 | */ 88 | @WithDefault("true") 89 | boolean cacheEnabled(); 90 | 91 | /** 92 | * MyBatis lazyLoadingEnabled 93 | */ 94 | @WithDefault("false") 95 | boolean lazyLoadingEnabled(); 96 | 97 | /** 98 | * MyBatis aggressiveLazyLoading 99 | */ 100 | @WithDefault("false") 101 | boolean aggressiveLazyLoading(); 102 | 103 | /** 104 | * MyBatis useColumnLabel 105 | */ 106 | @WithDefault("true") 107 | boolean useColumnLabel(); 108 | 109 | /** 110 | * MyBatis useGeneratedKeys 111 | */ 112 | @WithDefault("false") 113 | boolean useGeneratedKeys(); 114 | 115 | /** 116 | * MyBatis autoMappingBehavior 117 | */ 118 | @WithDefault("PARTIAL") 119 | AutoMappingBehavior autoMappingBehavior(); 120 | 121 | /** 122 | * MyBatis autoMappingUnknownColumnBehavior 123 | */ 124 | @WithDefault("NONE") 125 | AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior(); 126 | 127 | /** 128 | * MyBatis defaultExecutorType 129 | */ 130 | @WithDefault("SIMPLE") 131 | ExecutorType defaultExecutorType(); 132 | 133 | /** 134 | * MyBatis defaultStatementTimeout 135 | */ 136 | Optional defaultStatementTimeout(); 137 | 138 | /** 139 | * MyBatis defaultFetchSize 140 | */ 141 | Optional defaultFetchSize(); 142 | 143 | /** 144 | * MyBatis defaultResultSetType 145 | */ 146 | Optional defaultResultSetType(); 147 | 148 | /** 149 | * MyBatis safeRowBoundsEnabled 150 | */ 151 | @WithDefault("false") 152 | boolean safeRowBoundsEnabled(); 153 | 154 | /** 155 | * MyBatis safeResultHandlerEnabled 156 | */ 157 | @WithDefault("true") 158 | boolean safeResultHandlerEnabled(); 159 | 160 | /** 161 | * MyBatis mapUnderscoreToCamelCase 162 | */ 163 | @WithDefault("false") 164 | boolean mapUnderscoreToCamelCase(); 165 | 166 | /** 167 | * MyBatis multipleResultSetsEnabled 168 | */ 169 | @WithDefault("true") 170 | boolean multipleResultSetsEnabled(); 171 | 172 | /** 173 | * MyBatis localCacheScope 174 | */ 175 | @WithDefault("SESSION") 176 | LocalCacheScope localCacheScope(); 177 | 178 | /** 179 | * MyBatis jdbcTypeForNull 180 | */ 181 | @WithDefault("OTHER") 182 | JdbcType jdbcTypeForNull(); 183 | 184 | /** 185 | * MyBatis lazyLoadTriggerMethods 186 | */ 187 | @WithDefault("equals,clone,hashCode,toString") 188 | Set lazyLoadTriggerMethods(); 189 | 190 | /** 191 | * MyBatis defaultScriptingLanguage 192 | */ 193 | @WithDefault("org.apache.ibatis.scripting.xmltags.XMLLanguageDriver") 194 | String defaultScriptingLanguage(); 195 | 196 | /** 197 | * MyBatis defaultEnumTypeHandler 198 | */ 199 | @WithDefault("org.apache.ibatis.type.EnumTypeHandler") 200 | String defaultEnumTypeHandler(); 201 | 202 | /** 203 | * MyBatis callSettersOnNulls 204 | */ 205 | @WithDefault("false") 206 | boolean callSettersOnNulls(); 207 | 208 | /** 209 | * MyBatis returnInstanceForEmptyRow 210 | */ 211 | @WithDefault("false") 212 | boolean returnInstanceForEmptyRow(); 213 | 214 | /** 215 | * MyBatis logPrefix 216 | */ 217 | Optional logPrefix(); 218 | 219 | /** 220 | * MyBatis logImpl 221 | */ 222 | Optional logImpl(); 223 | 224 | /** 225 | * MyBatis proxyFactory 226 | */ 227 | @WithDefault("JAVASSIST") 228 | String proxyFactory(); 229 | 230 | /** 231 | * MyBatis vfsImpl 232 | */ 233 | Optional vfsImpl(); 234 | 235 | /** 236 | * MyBatis useActualParamName 237 | */ 238 | @WithDefault("true") 239 | boolean useActualParamName(); 240 | 241 | /** 242 | * MyBatis configurationFactory 243 | */ 244 | Optional configurationFactory(); 245 | 246 | /** 247 | * MyBatis shrinkWhitespacesInSql 248 | */ 249 | @WithDefault("false") 250 | public boolean shrinkWhitespacesInSql(); 251 | 252 | /** 253 | * MyBatis defaultSqlProviderType 254 | */ 255 | Optional defaultSqlProviderType(); 256 | 257 | /** 258 | * MyBatis mapperLocations 259 | */ 260 | Optional> mapperLocations(); 261 | } 262 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/java/io/quarkiverse/mybatis/runtime/meta/MapperDataSource.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.mybatis.runtime.meta; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.TYPE) 10 | public @interface MapperDataSource { 11 | String value(); 12 | } 13 | -------------------------------------------------------------------------------- /mybatis/runtime/src/main/resources/META-INF/quarkus-extension.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "MyBatis SQL Mapper" 3 | metadata: 4 | icon-url: "https://raw.githubusercontent.com/mybatis/logo/master/logo-bird-ninja.svg" 5 | keywords: 6 | - "mybatis" 7 | guide: "https://quarkiverse.github.io/quarkiverse-docs/quarkus-mybatis/dev/index.html" 8 | categories: 9 | - "data" 10 | status: "stable" 11 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse 6 | quarkiverse-parent 7 | 20 8 | 9 | io.quarkiverse.mybatis 10 | quarkus-parent 11 | Quarkus - Parent 12 | 999-SNAPSHOT 13 | pom 14 | 15 | UTF-8 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 3.8.1 20 | 3.5.3 21 | 3.23.2 22 | 3.5.19 23 | 3.5.12 24 | 3.0.3 25 | 26 | 27 | :git:git@github.com:quarkiverse/quarkus-mybatis.git 28 | scm:git:git@github.com:quarkiverse/quarkus-mybatis.git 29 | https://github.com/quarkiverse/quarkus-mybatis 30 | HEAD 31 | 32 | 33 | mybatis 34 | mybatis-plus 35 | 36 | 37 | 38 | 39 | io.quarkus 40 | quarkus-bom 41 | ${quarkus.version} 42 | pom 43 | import 44 | 45 | 46 | org.mybatis 47 | mybatis 48 | ${mybatis.version} 49 | 50 | 51 | com.baomidou 52 | mybatis-plus 53 | ${mybatis-plus.version} 54 | 55 | 56 | com.baomidou 57 | mybatis-plus-jsqlparser 58 | ${mybatis-plus.version} 59 | 60 | 61 | ru.vyarus 62 | generics-resolver 63 | ${vyarus.version} 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | org.apache.maven.plugins 72 | maven-compiler-plugin 73 | ${compiler.plugin.version} 74 | 75 | 76 | io.quarkus 77 | quarkus-maven-plugin 78 | ${quarkus.version} 79 | 80 | 81 | org.apache.maven.plugins 82 | maven-surefire-plugin 83 | ${surefire.plugin.version} 84 | 85 | 86 | org.jboss.logmanager.LogManager 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | --------------------------------------------------------------------------------