├── .github └── workflows │ └── main.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── build.gradle ├── gradle.tar ├── gradle.tar.enc ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md ├── settings.gradle └── src ├── main └── kotlin │ └── io │ └── wkz │ └── kotlin │ └── mybatis │ ├── JsonArrayTypeHandler.kt │ ├── JsonListTypeHandler.kt │ ├── JsonObjectTypeHandler.kt │ └── MyBatisObjectMapper.kt └── test ├── kotlin └── io │ └── wkz │ └── kotlin │ └── mybatis │ ├── JsonArrayTypeHandlerTest.kt │ ├── JsonListTypeHandlerTest.kt │ ├── JsonObjectTypeHandlerTest.kt │ ├── MyBatisObjectMapperTest.kt │ ├── MybatisScanConfiguration.kt │ ├── dao │ ├── ArrayJsonDao.kt │ ├── ListJsonDao.kt │ └── ObjectJsonDao.kt │ └── entity │ └── Entity.kt └── resources ├── application.yaml └── sqlmap ├── mappers ├── ArrayJsonDao.xml ├── ListJsonDao.xml └── ObjectJsonDao.xml └── test.xml /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Cache SonarCloud packages 21 | uses: actions/cache@v1 22 | with: 23 | path: ~/.sonar/cache 24 | key: ${{ runner.os }}-sonar 25 | restore-keys: ${{ runner.os }}-sonar 26 | - name: Cache Gradle packages 27 | uses: actions/cache@v1 28 | with: 29 | path: ~/.gradle/caches 30 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 31 | restore-keys: ${{ runner.os }}-gradle 32 | - name: Start MySQL 33 | run: sudo systemctl start mysql.service 34 | - name: Build and analyze 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 37 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 38 | run: ./gradlew build sonarqube --info 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Gradle template 3 | .gradle 4 | /build/ 5 | 6 | # Ignore Gradle GUI config 7 | gradle-app.setting 8 | 9 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 10 | 11 | 12 | # Cache of project 13 | .gradletasknamecache 14 | 15 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 16 | # gradle/wrapper/gradle-wrapper.properties 17 | ### Kotlin template 18 | # Compiled class file 19 | *.class 20 | 21 | # Log file 22 | *.log 23 | 24 | # BlueJ files 25 | *.ctxt 26 | 27 | # Mobile Tools for Java (J2ME) 28 | .mtj.tmp/ 29 | 30 | # Package Files # 31 | *.jar 32 | !gradle-wrapper.jar 33 | *.war 34 | *.ear 35 | *.zip 36 | *.tar.gz 37 | *.rar 38 | 39 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 40 | hs_err_pid* 41 | out/ 42 | .idea/ 43 | mybatis-json-typehandler.iml 44 | 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | services: mysql 3 | before_install: 4 | - openssl aes-256-cbc -K $encrypted_0b8355631cb2_key -iv $encrypted_0b8355631cb2_iv 5 | -in gradle.tar.enc -out gradle.tar -d 6 | - tar xvf gradle.tar 7 | - mysql -e "create database if not exists test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 8 | use test; 9 | drop table if exists list_json_tbl; 10 | create table list_json_tbl( 11 | id int 12 | unsigned primary key unique auto_increment, 13 | listJson varchar(255) not null 14 | ) 15 | ENGINE = InnoDB 16 | DEFAULT CHARSET = utf8mb4 17 | COLLATE utf8mb4_general_ci; 18 | insert into list_json_tbl 19 | (listJson) 20 | values (''), 21 | ('[{\"name\":\"测试\",\"age\":13},{\"name\":\"测试2\",\"age\":14}]'); 22 | drop table if exists object_json_tbl; 23 | create table object_json_tbl 24 | ( 25 | id int 26 | unsigned primary key unique auto_increment, 27 | objectJson varchar(255) not null 28 | ) 29 | ENGINE = InnoDB 30 | DEFAULT CHARSET = utf8mb4 31 | COLLATE utf8mb4_general_ci; 32 | insert into object_json_tbl 33 | (objectJson) 34 | values (''), 35 | ('{\"name\":\"测试\",\"age\":13}'); 36 | drop table if exists array_json_tbl; 37 | create table array_json_tbl 38 | ( 39 | id int unsigned primary key unique auto_increment, 40 | arrayJson varchar(255) not null 41 | ) 42 | engine = InnoDB 43 | default charset = utf8mb4 44 | collate utf8mb4_general_ci; 45 | insert into array_json_tbl (arrayJson) 46 | values (''), 47 | ('[{\"name\":\"测试\",\"age\":13},{\"name\":\"测试2\",\"age\":14}]');" 48 | after_success: 49 | - bash <(curl -s https://codecov.io/bash) 50 | before_cache: 51 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 52 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 53 | cache: 54 | directories: 55 | - "$HOME/.gradle/caches/" 56 | - "$HOME/.gradle/wrapper/" 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Tyrael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | kotlin_version = '1.3.50' 4 | scm_url = 'https://github.com/wangkezun/mybatis-json-typehandler' 5 | scm_connection = 'scm:git:git@github.com:wangkezun/mybatis-json-typehandler.git' 6 | scm_developerConnection = 'scm:git:git@github.com:wangkezun/mybatis-json-typehandler.git' 7 | scm_tag = 'HEAD' 8 | issueUrl = 'https://github.com/wangkezun/mybatis-json-typehandler/issues' 9 | } 10 | 11 | repositories { 12 | mavenCentral() 13 | jcenter() 14 | } 15 | } 16 | 17 | plugins { 18 | id "org.jetbrains.kotlin.jvm" version "1.3.50" 19 | id 'jacoco' 20 | id 'maven-publish' 21 | id 'maven' 22 | id 'signing' 23 | id 'org.jetbrains.dokka' version "0.10.0" 24 | id "org.sonarqube" version "3.4.0.2513" 25 | } 26 | 27 | 28 | group = 'io.wkz.kotlin' 29 | version = '1.0.2' 30 | 31 | repositories { 32 | mavenCentral() 33 | jcenter() 34 | } 35 | 36 | dependencies { 37 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 38 | compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" 39 | compile group: 'org.mybatis', name: 'mybatis', version: '3.5.6' 40 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.6.1' 41 | compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.9.7' 42 | testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.3.1' 43 | testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.0.6.RELEASE' 44 | testCompile group: 'mysql', name: 'mysql-connector-java', version: '8.0.13' 45 | testCompile group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '1.3.2' 46 | testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.3.1' 47 | } 48 | 49 | jacocoTestReport { 50 | reports { 51 | xml.enabled = true 52 | html.enabled = false 53 | } 54 | } 55 | 56 | compileKotlin { 57 | kotlinOptions.jvmTarget = "1.8" 58 | } 59 | compileTestKotlin { 60 | kotlinOptions.jvmTarget = "1.8" 61 | } 62 | test { 63 | useJUnitPlatform() 64 | } 65 | 66 | // build.gradle 67 | task sourceJar(type: Jar) { 68 | from sourceSets.main.allSource 69 | } 70 | 71 | check.dependsOn jacocoTestReport 72 | 73 | dokka { 74 | outputFormat = 'javadoc' 75 | outputDirectory = javadoc.destinationDir 76 | inputs.dir 'src/main/kotlin' 77 | cacheRoot = 'default' 78 | } 79 | 80 | task packageJavadoc(type: Jar, dependsOn: dokka) { 81 | classifier = 'javadoc' 82 | from javadoc.destinationDir 83 | } 84 | 85 | publishing { 86 | publications { 87 | mavenJava(MavenPublication) { 88 | from components.java 89 | pom { 90 | name = 'mybatis-json-typehandler' 91 | url = 'https://github.com/wangkezun/mybatis-json-typehandler' 92 | description = 'A Mybatis TypeHandler for json object and json array' 93 | scm { 94 | url = scm_url 95 | connection = scm_connection 96 | developerConnection = scm_developerConnection 97 | tag = scm_tag 98 | } 99 | 100 | license { 101 | name = 'MIT Licence' 102 | url = 'https://raw.githubusercontent.com/wangkezun/mybatis-json-typehandler/master/LICENSE' 103 | distribution = 'repo' 104 | } 105 | developers { 106 | developer { 107 | id= 'wangkezun' 108 | name = 'Wang Kezun' 109 | email = 'wangkezun@gmail.com' 110 | } 111 | } 112 | issueManagement { 113 | system = 'GitHub Issues' 114 | url = issueUrl 115 | } 116 | } 117 | artifact sourceJar { 118 | classifier "sources" 119 | } 120 | artifact packageJavadoc { 121 | classifier "javadoc" 122 | } 123 | } 124 | } 125 | repositories { 126 | maven { 127 | if (project.version.endsWith('-SNAPSHOT')) { 128 | url = "https://oss.sonatype.org/content/repositories/snapshots" 129 | } else { 130 | url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 131 | } 132 | credentials { 133 | username findProperty("ossrhUsername") ?: System.getenv("OSSRH_USERNAME") 134 | password findProperty("ossrhPassword") ?: System.getenv("OSSRH_PASSWORD") 135 | } 136 | } 137 | } 138 | } 139 | signing { 140 | required { gradle.taskGraph.hasTask("publishing") } 141 | sign publishing.publications.mavenJava 142 | } 143 | sonarqube { 144 | properties { 145 | property "sonar.projectKey", "wangkezun_mybatis-json-typehandler" 146 | property "sonar.organization", "wangkezun" 147 | property "sonar.host.url", "https://sonarcloud.io" 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /gradle.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangkezun/mybatis-json-typehandler/d6bfbcd1d8ee4e16bd012379d92a9d7350a71337/gradle.tar -------------------------------------------------------------------------------- /gradle.tar.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangkezun/mybatis-json-typehandler/d6bfbcd1d8ee4e16bd012379d92a9d7350a71337/gradle.tar.enc -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangkezun/mybatis-json-typehandler/d6bfbcd1d8ee4e16bd012379d92a9d7350a71337/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Oct 20 17:32:34 CST 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Mybatis-Json-TypeHandler [![Build Status](https://travis-ci.org/wangkezun/mybatis-json-typehandler.svg?branch=master)](https://travis-ci.org/wangkezun/mybatis-json-typehandler) [![Codecov](https://img.shields.io/codecov/c/github/wangkezun/mybatis-json-typehandler.svg)](https://github.com/wangkezun/mybatis-json-typehandler) [![GitHub license](https://img.shields.io/github/license/wangkezun/mybatis-json-typehandler.svg)](https://github.com/wangkezun/mybatis-json-typehandler/blob/master/LICENSE)[![DepShield Badge](https://depshield.sonatype.org/badges/wangkezun/mybatis-json-typehandler/depshield.svg)](https://depshield.github.io) 2 | 3 | --- 4 | 5 | ## 目的 6 | 开发过程中经常会遇到一对多的关系,大部分情况下这种关系都存在一张表中,通过id等关系进行关联。 7 | 但是在某些特殊情况下,单独为这种情况生成一个表并不是非常必须,而且也不会对这种关系进行查询。 8 | 此时可以考虑将数据存在一对多的一这个表中,把多的数据存成JSON结构。 9 | 但是MyBatis并没有对这种情况提供原生支持。此项目提供了一种自动序列化与反序列化的功能。 10 | 调用时仅需要在mapper中配置好即可使用。 11 | 12 | ## 依赖 13 | 项目依赖于MyBatis、Jackson。基于Kotlin语言。java8+ 14 | 15 | ## 用法 16 | 1. 引入依赖 17 | * maven 18 | ```xml 19 | 20 | io.wkz.kotlin 21 | mybatis-json-typehandler 22 | 1.0.1 23 | 24 | ``` 25 | 26 | * gradle 27 | ```groovy 28 | compile 'io.wkz.kotlin:mybatis-json-typehandler:1.0.1' 29 | ``` 30 | 1. 实体类 31 | 32 | 与正常的实体类没有任何区别 33 | 34 | ```java 35 | public class Data { 36 | private int id; 37 | //数据库中序列化为JSON Object 38 | private JsonObject targetObject; 39 | // 数据库中序列化为JSON Array 40 | private List targetList; 41 | //数据库中序列化为JSON Array 42 | private JsonObject[] tartetArray; 43 | } 44 | public class JsonObject { 45 | private String xxx; 46 | private int yyy; 47 | } 48 | ``` 49 | ```kotlin 50 | data class Data(val id: Int = 0, val targetObject: JsonObject? = null, val targetList:List? =null, val targetArray:Array? = null) 51 | data class JsonObject(val xxx:String, val yyy:Int) 52 | ``` 53 | 2. mapper 54 | 55 | 重点修改在#{}以及resultMap的result中。 56 | 明确定义javaType以及typeHandler即可,如下所示 57 | ```xml 58 | 61 | 62 | 63 | 65 | 67 | 69 | 70 | 71 | insert into tbl_name (targetObject,targetList) value 72 | (#{targetObject,javaType=JsonObject,jdbcType=VARCHAR,typeHandler=io.wkz.kotlin.mybatis.JsonObjectTypeHandler}, 73 | #{targetList,javaType=JsonObject,jdbcType=VARCHAR,typeHandler=io.wkz.kotlin.mybatis.JsonListTypeHandler}, 74 | #{targetArray,javaType=JsonObject,jdbcType=VARCHAR,typeHandler=io.wkz.kotlin.mybatis.JsonArrayTypeHandler}, 75 | ) 76 | 77 | 82 | 83 | ``` 84 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'mybatis-json-typehandler' 2 | 3 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wkz/kotlin/mybatis/JsonArrayTypeHandler.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import com.fasterxml.jackson.databind.ObjectReader 4 | import com.fasterxml.jackson.databind.ObjectWriter 5 | import org.apache.ibatis.type.BaseTypeHandler 6 | import org.apache.ibatis.type.JdbcType 7 | import org.apache.ibatis.type.MappedJdbcTypes 8 | import java.sql.CallableStatement 9 | import java.sql.PreparedStatement 10 | import java.sql.ResultSet 11 | import java.sql.SQLException 12 | 13 | /** 14 | * 针对object的typeHandler。 15 | * 16 | * @author wangkezun(wangkezun@gmail.com) 17 | * * 18 | * @since 1.0 19 | * @param clazz 需要进行转换的java类 20 | */ 21 | @MappedJdbcTypes(JdbcType.VARCHAR) 22 | class JsonArrayTypeHandler(clazz: Class) : BaseTypeHandler>() { 23 | private val arrayReader: ObjectReader 24 | private val arrayWriter: ObjectWriter 25 | 26 | init { 27 | val objectMapper = MyBatisObjectMapper.objectMapper 28 | val type = objectMapper.typeFactory.constructArrayType(clazz) 29 | arrayReader = objectMapper.readerFor(type) 30 | arrayWriter = objectMapper.writerFor(type) 31 | } 32 | 33 | /** 34 | * json 转换成对象 35 | */ 36 | private fun jsonToObject(json: String?): Array? { 37 | return if (!json.isNullOrBlank()) { 38 | arrayReader.readValue(json) 39 | } else { 40 | null 41 | } 42 | } 43 | 44 | @Throws(SQLException::class) 45 | override fun setNonNullParameter(ps: PreparedStatement, 46 | i: Int, 47 | parameter: Array?, 48 | jdbcType: JdbcType) { 49 | 50 | ps.setString(i, arrayWriter.writeValueAsString(parameter)) 51 | } 52 | 53 | @Throws(SQLException::class) 54 | override fun getNullableResult(cs: CallableStatement, columnIndex: Int): Array? { 55 | val json = cs.getString(columnIndex) 56 | 57 | return jsonToObject(json) 58 | } 59 | 60 | @Throws(SQLException::class) 61 | override fun getNullableResult(rs: ResultSet, columnIndex: Int): Array? { 62 | val json = rs.getString(columnIndex) 63 | 64 | return jsonToObject(json) 65 | } 66 | 67 | @Throws(SQLException::class) 68 | override fun getNullableResult(rs: ResultSet, columnName: String): Array? { 69 | val json = rs.getString(columnName) 70 | 71 | return jsonToObject(json) 72 | } 73 | 74 | override fun setParameter(ps: PreparedStatement?, i: Int, parameter: Array?, jdbcType: JdbcType?) { 75 | if (parameter == null) { 76 | ps?.setString(i, "[]") 77 | } else { 78 | super.setParameter(ps, i, parameter, jdbcType) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wkz/kotlin/mybatis/JsonListTypeHandler.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import com.fasterxml.jackson.databind.ObjectReader 4 | import com.fasterxml.jackson.databind.ObjectWriter 5 | import org.apache.ibatis.type.BaseTypeHandler 6 | import org.apache.ibatis.type.JdbcType 7 | import org.apache.ibatis.type.MappedJdbcTypes 8 | import java.sql.CallableStatement 9 | import java.sql.PreparedStatement 10 | import java.sql.ResultSet 11 | import java.sql.SQLException 12 | 13 | /** 14 | * 15 | * @author wangkezun(wangkezun@gmail.com) 16 | * @since 1.0 17 | */ 18 | @MappedJdbcTypes(JdbcType.VARCHAR) 19 | class JsonListTypeHandler(clazz: Class) : BaseTypeHandler>() { 20 | private val listReader: ObjectReader 21 | private val listWriter: ObjectWriter 22 | 23 | 24 | init { 25 | val objectMapper = MyBatisObjectMapper.objectMapper 26 | val type = objectMapper.typeFactory.constructCollectionType(List::class.java, clazz) 27 | listReader = objectMapper.readerFor(type) 28 | listWriter = objectMapper.writerFor(type) 29 | } 30 | 31 | /** 32 | * json 转换成对象 33 | */ 34 | private fun jsonToList(json: String?): List? { 35 | return if (!json.isNullOrBlank()) { 36 | listReader.readValue(json) 37 | } else{ 38 | emptyList() 39 | } 40 | 41 | } 42 | 43 | @Throws(SQLException::class) 44 | override fun setNonNullParameter(ps: PreparedStatement, 45 | i: Int, 46 | parameter: List?, 47 | jdbcType: JdbcType) { 48 | 49 | ps.setString(i, listWriter.writeValueAsString(parameter)) 50 | } 51 | 52 | @Throws(SQLException::class) 53 | override fun getNullableResult(cs: CallableStatement, columnIndex: Int): List? { 54 | val json = cs.getString(columnIndex) 55 | 56 | return jsonToList(json) 57 | } 58 | 59 | @Throws(SQLException::class) 60 | override fun getNullableResult(rs: ResultSet, columnIndex: Int): List? { 61 | val json = rs.getString(columnIndex) 62 | 63 | return jsonToList(json) 64 | } 65 | 66 | @Throws(SQLException::class) 67 | override fun getNullableResult(rs: ResultSet, columnName: String): List? { 68 | val json = rs.getString(columnName) 69 | 70 | return jsonToList(json) 71 | } 72 | 73 | override fun setParameter(ps: PreparedStatement?, i: Int, parameter: List?, jdbcType: JdbcType?) { 74 | if (parameter == null) { 75 | ps?.setString(i, "[]") 76 | } else { 77 | super.setParameter(ps, i, parameter, jdbcType) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wkz/kotlin/mybatis/JsonObjectTypeHandler.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import org.apache.ibatis.type.BaseTypeHandler 4 | import org.apache.ibatis.type.JdbcType 5 | import org.apache.ibatis.type.MappedJdbcTypes 6 | import java.sql.CallableStatement 7 | import java.sql.PreparedStatement 8 | import java.sql.ResultSet 9 | import java.sql.SQLException 10 | 11 | /** 12 | * 针对object的typeHandler。 13 | * 14 | * @author wangkezun(wangkezun@gmail.com) 15 | * * 16 | * @since 1.0 17 | * @param clazz 需要进行转换的java类 18 | */ 19 | @MappedJdbcTypes(JdbcType.VARCHAR) 20 | class JsonObjectTypeHandler(clazz: Class) : BaseTypeHandler() { 21 | private val objectReader = MyBatisObjectMapper.objectMapper.readerFor(clazz) 22 | private val objectWriter = MyBatisObjectMapper.objectMapper.writerFor(clazz) 23 | 24 | /** 25 | * json 转换成对象 26 | */ 27 | private fun jsonToObject(json: String?): Any? { 28 | return if (!json.isNullOrBlank()) { 29 | objectReader.readValue(json) 30 | } else { 31 | null 32 | } 33 | } 34 | 35 | @Throws(SQLException::class) 36 | override fun setNonNullParameter(ps: PreparedStatement, 37 | i: Int, 38 | parameter: Any?, 39 | jdbcType: JdbcType) { 40 | 41 | ps.setString(i, objectWriter.writeValueAsString(parameter)) 42 | } 43 | 44 | @Throws(SQLException::class) 45 | override fun getNullableResult(cs: CallableStatement, columnIndex: Int): Any? { 46 | val json = cs.getString(columnIndex) 47 | 48 | return jsonToObject(json) 49 | } 50 | 51 | @Throws(SQLException::class) 52 | override fun getNullableResult(rs: ResultSet, columnIndex: Int): Any? { 53 | val json = rs.getString(columnIndex) 54 | 55 | return jsonToObject(json) 56 | } 57 | 58 | @Throws(SQLException::class) 59 | override fun getNullableResult(rs: ResultSet, columnName: String): Any? { 60 | val json = rs.getString(columnName) 61 | 62 | return jsonToObject(json) 63 | } 64 | 65 | override fun setParameter(ps: PreparedStatement?, i: Int, parameter: Any, jdbcType: JdbcType?) { 66 | if (parameter == null) { 67 | ps?.setString(i, "") 68 | } else { 69 | super.setParameter(ps, i, parameter, jdbcType) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wkz/kotlin/mybatis/MyBatisObjectMapper.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import com.fasterxml.jackson.module.kotlin.KotlinModule 5 | 6 | /** 7 | * This class generate a [ObjectMapper] to serialize or deserialize object or list. 8 | * TypeHandler don't use it directly, 9 | * but use it to create [com.fasterxml.jackson.databind.ObjectReader] and 10 | * [com.fasterxml.jackson.databind.ObjectWriter] to ensure thread-safe and optimize serialize or deserialize speed 11 | * @author wangkezun(wangkezun@gmail.com) 12 | * @since 1.0 13 | */ 14 | internal object MyBatisObjectMapper { 15 | 16 | val objectMapper = ObjectMapper().apply{ 17 | // You could change some config in this block like this 18 | //this.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 19 | this.registerModule(KotlinModule()) 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/JsonArrayTypeHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import io.wkz.kotlin.mybatis.dao.ArrayJsonDao 4 | import io.wkz.kotlin.mybatis.entity.ArrayJson 5 | import io.wkz.kotlin.mybatis.entity.SubObject 6 | import org.junit.jupiter.api.Assertions.* 7 | import org.junit.jupiter.api.DisplayName 8 | import org.junit.jupiter.api.Test 9 | import org.junit.jupiter.api.extension.ExtendWith 10 | import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 11 | import org.springframework.beans.factory.annotation.Autowired 12 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration 13 | import org.springframework.boot.test.context.SpringBootTest 14 | import org.springframework.test.context.junit.jupiter.SpringExtension 15 | 16 | /** 17 | * 18 | * @author 王可尊 19 | * @since 1.0 20 | */ 21 | @DisplayName("Test JsonArrayTypeHandler") 22 | @ExtendWith(SpringExtension::class) 23 | @SpringBootTest(classes = [DataSourceAutoConfiguration::class, MybatisAutoConfiguration::class, MybatisScanConfiguration::class]) 24 | class JsonArrayTypeHandlerTest { 25 | 26 | @Autowired 27 | private lateinit var arrayJsonDao: ArrayJsonDao 28 | 29 | @Test 30 | fun testInsertJsonListAsVarchar() { 31 | val emptyObject = ArrayJson() 32 | arrayJsonDao.add(emptyObject) 33 | assertNotEquals(0, emptyObject.id) 34 | val notEmptyObject = ArrayJson(arrayJson = arrayOf(SubObject("新增", 14), SubObject("新增2", 15))) 35 | arrayJsonDao.add(notEmptyObject) 36 | assertNotEquals(0, emptyObject.id) 37 | } 38 | 39 | @Test 40 | fun testGetJsonListFromVarchar() { 41 | val emptyListResult = arrayJsonDao.get(1) 42 | assertNotNull(emptyListResult) 43 | assertEquals(1, emptyListResult.id) 44 | println(emptyListResult) 45 | assertNull(emptyListResult.arrayJson) 46 | 47 | val notEmptyListResult = arrayJsonDao.get(2) 48 | assertNotNull(notEmptyListResult) 49 | val (id, listJson) = notEmptyListResult 50 | assertEquals(2, id) 51 | assertNotNull(listJson) 52 | assertEquals(2, listJson!!.size) 53 | assertEquals(SubObject("测试", 13), listJson[0]) 54 | assertEquals(SubObject("测试2", 14), listJson[1]) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/JsonListTypeHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import io.wkz.kotlin.mybatis.dao.ListJsonDao 4 | import io.wkz.kotlin.mybatis.entity.ListJson 5 | import io.wkz.kotlin.mybatis.entity.SubObject 6 | import org.junit.jupiter.api.Assertions.* 7 | import org.junit.jupiter.api.DisplayName 8 | import org.junit.jupiter.api.Test 9 | import org.junit.jupiter.api.extension.ExtendWith 10 | import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 11 | import org.springframework.beans.factory.annotation.Autowired 12 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration 13 | import org.springframework.boot.test.context.SpringBootTest 14 | import org.springframework.test.context.junit.jupiter.SpringExtension 15 | 16 | /** 17 | * 18 | * @author 王可尊 19 | * @since 1.0 20 | */ 21 | @DisplayName("Test JsonListTypeHandler") 22 | @ExtendWith(SpringExtension::class) 23 | @SpringBootTest(classes = [DataSourceAutoConfiguration::class, MybatisAutoConfiguration::class, MybatisScanConfiguration::class]) 24 | class JsonListTypeHandlerTest { 25 | 26 | @Autowired 27 | private lateinit var listJsonDao: ListJsonDao 28 | 29 | @Test 30 | fun testInsertJsonListAsVarchar() { 31 | val emptyObject = ListJson() 32 | listJsonDao.add(emptyObject) 33 | assertNotEquals(0, emptyObject.id) 34 | val notEmptyObject = ListJson(listJson = listOf(SubObject("新增", 14), SubObject("新增2", 15))) 35 | listJsonDao.add(notEmptyObject) 36 | assertNotEquals(0, emptyObject.id) 37 | } 38 | 39 | @Test 40 | fun testGetJsonListFromVarchar() { 41 | val emptyListResult = listJsonDao.get(1) 42 | assertNotNull(emptyListResult) 43 | assertEquals(1, emptyListResult.id) 44 | println(emptyListResult) 45 | assertNotNull(emptyListResult.listJson) 46 | assertEquals(0, emptyListResult.listJson!!.size) 47 | 48 | val notEmptyListResult = listJsonDao.get(2) 49 | assertNotNull(notEmptyListResult) 50 | val (id, listJson) = notEmptyListResult 51 | assertEquals(2, id) 52 | assertNotNull(listJson) 53 | assertEquals(2, listJson!!.size) 54 | assertEquals(SubObject("测试", 13), listJson[0]) 55 | assertEquals(SubObject("测试2", 14), listJson[1]) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/JsonObjectTypeHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import io.wkz.kotlin.mybatis.dao.ObjectJsonDao 4 | import io.wkz.kotlin.mybatis.entity.ObjectJson 5 | import io.wkz.kotlin.mybatis.entity.SubObject 6 | import org.apache.ibatis.io.Resources 7 | import org.apache.ibatis.jdbc.ScriptRunner 8 | import org.apache.ibatis.session.SqlSessionFactory 9 | import org.junit.Assert.* 10 | import org.junit.BeforeClass 11 | import org.junit.jupiter.api.Assertions.assertAll 12 | import org.junit.jupiter.api.DisplayName 13 | import org.junit.jupiter.api.Test 14 | import org.junit.jupiter.api.extension.ExtendWith 15 | import org.junit.jupiter.api.function.Executable 16 | import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 17 | import org.springframework.beans.factory.annotation.Autowired 18 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration 19 | import org.springframework.boot.test.context.SpringBootTest 20 | import org.springframework.test.context.junit.jupiter.SpringExtension 21 | 22 | /** 23 | * 24 | * @author 王可尊 25 | * @since 1.0 26 | */ 27 | @DisplayName("Test JsonObjectTypeHandler") 28 | @ExtendWith(SpringExtension::class) 29 | @SpringBootTest(classes = [DataSourceAutoConfiguration::class, MybatisAutoConfiguration::class, MybatisScanConfiguration::class]) 30 | internal class JsonObjectTypeHandlerTest { 31 | @Autowired 32 | private lateinit var objectJsonDao: ObjectJsonDao 33 | 34 | @Test 35 | fun testInsertJsonObjectAsVarchar() { 36 | val notEmptyObjectJson = ObjectJson(objectJson = SubObject("测试", 13)) 37 | objectJsonDao.add(notEmptyObjectJson) 38 | assertNotEquals(0, notEmptyObjectJson.id) 39 | val emptyObjectJson = ObjectJson() 40 | objectJsonDao.add(emptyObjectJson) 41 | assertNotEquals(0, emptyObjectJson.id) 42 | } 43 | 44 | @Test 45 | fun testGetJsonObjectFromVarchar() { 46 | val emptyObject = objectJsonDao.get(1) 47 | assertAll( 48 | Executable { assertNotNull(emptyObject) }, 49 | Executable { assertEquals(1, emptyObject.id) }, 50 | Executable { assertNull(emptyObject.objectJson) } 51 | ) 52 | val notEmptyObject = objectJsonDao.get(2) 53 | assertAll( 54 | Executable { assertNotNull(notEmptyObject) }, 55 | Executable { assertEquals(2, notEmptyObject.id) }, 56 | Executable { assertNotNull(notEmptyObject.objectJson) }, 57 | Executable { assertEquals("测试", notEmptyObject.objectJson!!.name) }, 58 | Executable { assertEquals(13, notEmptyObject.objectJson!!.age) } 59 | ) 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/MyBatisObjectMapperTest.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import org.junit.jupiter.api.Assertions.assertNotNull 4 | import org.junit.jupiter.api.DisplayName 5 | import org.junit.jupiter.api.Test 6 | import org.mybatis.spring.annotation.MapperScan 7 | 8 | /** 9 | * @author wangkezun(wangkezun@gmail.com) 10 | * @since 1.0 11 | */ 12 | @DisplayName("MyBatisObjectMapper Test Cases") 13 | @MapperScan("io.wkz.kotlin.mybatis.dao") 14 | internal class MyBatisObjectMapperTest { 15 | 16 | @Test 17 | @DisplayName("Test get ObjectMapper success") 18 | fun getObjectMapper() { 19 | assertNotNull(MyBatisObjectMapper.objectMapper) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/MybatisScanConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis 2 | 3 | import org.mybatis.spring.annotation.MapperScan 4 | import org.springframework.context.annotation.Configuration 5 | 6 | /** 7 | * 8 | * @author 王可尊 9 | * @since 1.0 10 | */ 11 | @Configuration 12 | @MapperScan("io.wkz.kotlin.mybatis.dao") 13 | open class MybatisScanConfiguration { 14 | } 15 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/dao/ArrayJsonDao.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis.dao 2 | 3 | import io.wkz.kotlin.mybatis.entity.ArrayJson 4 | 5 | /** 6 | * 7 | * @author 王可尊 8 | * @since 1.0 9 | */ 10 | interface ArrayJsonDao { 11 | fun add(listJson: ArrayJson):Int 12 | fun get(id:Int):ArrayJson 13 | } 14 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/dao/ListJsonDao.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis.dao 2 | 3 | import io.wkz.kotlin.mybatis.entity.ListJson 4 | 5 | /** 6 | * 7 | * @author 王可尊 8 | * @since 1.0 9 | */ 10 | interface ListJsonDao { 11 | fun add(listJson:ListJson):Int 12 | fun get(id:Int):ListJson 13 | } 14 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/dao/ObjectJsonDao.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis.dao 2 | 3 | import io.wkz.kotlin.mybatis.entity.ObjectJson 4 | 5 | /** 6 | * 7 | * @author 王可尊 8 | * @since 1.0 9 | */ 10 | interface ObjectJsonDao { 11 | fun add(objectJson: ObjectJson):Int 12 | fun get(id:Int):ObjectJson 13 | } 14 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wkz/kotlin/mybatis/entity/Entity.kt: -------------------------------------------------------------------------------- 1 | package io.wkz.kotlin.mybatis.entity 2 | 3 | /** 4 | * 5 | * @author 王可尊 6 | * @since 1.0 7 | */ 8 | data class ObjectJson(val id: Int = 0, val objectJson: SubObject? = null) 9 | 10 | data class SubObject(val name: String, val age: Int) 11 | 12 | data class ListJson(val id: Int = 0, val listJson: List? = null) 13 | 14 | data class ArrayJson(val id: Int = 0, val arrayJson: Array? = null) { 15 | override fun equals(other: Any?): Boolean { 16 | if (this === other) return true 17 | if (javaClass != other?.javaClass) return false 18 | 19 | other as ArrayJson 20 | 21 | if (id != other.id) return false 22 | if (arrayJson != null) { 23 | if (other.arrayJson == null) return false 24 | if (!arrayJson.contentEquals(other.arrayJson)) return false 25 | } else if (other.arrayJson != null) return false 26 | 27 | return true 28 | } 29 | 30 | override fun hashCode(): Int { 31 | var result = id 32 | result = 31 * result + (arrayJson?.contentHashCode() ?: 0) 33 | return result 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: com.mysql.cj.jdbc.Driver 4 | url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true 5 | username: root 6 | password: root 7 | mybatis: 8 | mapper-locations: classpath:sqlmap/mappers/*.xml 9 | config-location: classpath:sqlmap/test.xml -------------------------------------------------------------------------------- /src/test/resources/sqlmap/mappers/ArrayJsonDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | insert into array_json_tbl (arrayJson) value 12 | ( 13 | #{arrayJson,javaType=io.wkz.kotlin.mybatis.entity.SubObject,jdbcType=VARCHAR,typeHandler=io.wkz.kotlin.mybatis.JsonArrayTypeHandler}) 14 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/sqlmap/mappers/ListJsonDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | insert into list_json_tbl (listJson) value 12 | ( 13 | #{listJson,javaType=io.wkz.kotlin.mybatis.entity.SubObject,jdbcType=VARCHAR,typeHandler=io.wkz.kotlin.mybatis.JsonListTypeHandler}) 14 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/sqlmap/mappers/ObjectJsonDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | insert into object_json_tbl (objectJson) value 12 | ( 13 | #{objectJson,javaType=io.wkz.kotlin.mybatis.entity.SubObject,jdbcType=VARCHAR,typeHandler=io.wkz.kotlin.mybatis.JsonObjectTypeHandler}) 14 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/sqlmap/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------