From 7fe4a2263596e59463aa513b3426a22c4ef1008c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 20:25:48 +0000 Subject: [PATCH 01/13] chore(deps): update dependency maven to v3.9.9 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index fd516637..01aa6654 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -16,5 +16,5 @@ # under the License. wrapperVersion=3.3.2 distributionType=source -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar From d89947cbfaabe94af3f7e61aa7ff9803b5042ec8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 23:13:36 +0000 Subject: [PATCH 02/13] chore(deps): update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.4.0 --- .../mybatis-spring-boot-sample-war/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-war/pom.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-war/pom.xml index 6f082633..88038ca9 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-war/pom.xml +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-war/pom.xml @@ -91,7 +91,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.3.1 + 3.4.0 org.codehaus.cargo From 47759bc7284bbc1506db88d26b38b8223388f65e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:57:24 +0000 Subject: [PATCH 03/13] chore(deps): update dependency org.jetbrains.kotlin:kotlin-maven-plugin to v2.0.20 --- .../mybatis-spring-boot-sample-kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-kotlin/pom.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-kotlin/pom.xml index ea89c536..49b82628 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-kotlin/pom.xml +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-kotlin/pom.xml @@ -28,7 +28,7 @@ mybatis-spring-boot-sample-kotlin org.mybatis.spring.boot.sample.kotlin - 2.0.10 + 2.0.20 From 061dca3bda67953bab4d17a644494c4e11a45bff Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:58:35 +0000 Subject: [PATCH 04/13] fix(deps): update spring boot to v3.3.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f3fb83db..5b1f2daa 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ 1.2.4 2.1.2 1.0.4 - 3.3.2 + 3.3.3 --add-opens java.base/java.lang=ALL-UNNAMED -Dfile.encoding=UTF-8 From 337e6b0ab472470d51a2e4527472a83c7b236710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Wed, 7 Aug 2024 21:20:03 +0800 Subject: [PATCH 05/13] :sparkles: Support annotation based on MyBatis for Spring Boot 3 Native https://github.com/mybatis/spring-boot-starter/issues/994 --- .github/workflows/native.yaml | 73 +++++ ...BeanFactoryInitializationAotProcessor.java | 138 ++++++++++ ...MyBatisMapperFactoryBeanPostProcessor.java | 87 ++++++ .../mybatis-reflection.json | 14 + .../native-image.properties | 17 ++ .../resources/META-INF/spring/aot.factories | 2 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../LICENSE_HEADER | 13 + .../format.xml | 22 ++ .../pom.xml | 176 ++++++++++++ .../SampleAnnotationApplication.java | 43 +++ .../graalvm/annotation/domain/City.java | 72 +++++ .../graalvm/annotation/mapper/CityMapper.java | 33 +++ .../src/main/resources/application.properties | 18 ++ .../src/main/resources/data.sql | 17 ++ .../src/main/resources/schema.sql | 20 ++ .../annotation/CaptureSystemOutput.java | 255 ++++++++++++++++++ .../SampleMybatisApplicationMainTest.java | 38 +++ .../SampleMybatisApplicationTest.java | 40 +++ .../annotation/mapper/CityMapperTest.java | 48 ++++ .../mapper/MapperTestApplication.java | 34 +++ mybatis-spring-boot-samples/pom.xml | 3 +- pom.xml | 1 + 23 files changed, 1164 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/native.yaml create mode 100644 mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java create mode 100644 mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisMapperFactoryBeanPostProcessor.java create mode 100644 mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/mybatis-reflection.json create mode 100644 mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/native-image.properties create mode 100644 mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/LICENSE_HEADER create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/format.xml create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/pom.xml create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/SampleAnnotationApplication.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/domain/City.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/mapper/CityMapper.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/application.properties create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/data.sql create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/schema.sql create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/extensions/annotation/CaptureSystemOutput.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationMainTest.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationTest.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/CityMapperTest.java create mode 100644 mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/MapperTestApplication.java diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml new file mode 100644 index 00000000..9a911e3a --- /dev/null +++ b/.github/workflows/native.yaml @@ -0,0 +1,73 @@ +# +# Copyright 2015-2024 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: Spring Boot Native Support Samples + +on: [ push, pull_request ] + +jobs: + test-ubuntu: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, macOS-latest ] + java: [ 17.0.9, 21.0.2, 22.0.2 ] + fail-fast: false + max-parallel: 5 + name: Test GraalVM JDK ${{ matrix.java }}, ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Ubuntu Set up JDK + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + JAVA_HOME=$RUNNER_WORKSPACE/.graalvm + echo $JAVA_HOME + mkdir -p $JAVA_HOME + echo "JAVA_HOME=$JAVA_HOME" >> $GITHUB_ENV + curl -L -o graalvm.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${{ matrix.java }}/graalvm-community-jdk-${{ matrix.java }}_linux-x64_bin.tar.gz + tar -zxvf graalvm.tar.gz -C $JAVA_HOME --strip-components=1 + ls -lh $JAVA_HOME + mvn -v + + - name: MacOS Set up JDK + if: ${{ matrix.os == 'macOS-latest' }} + run: | + JAVA_HOME=$RUNNER_WORKSPACE/.graalvm + echo $JAVA_HOME + mkdir -p $JAVA_HOME + curl -L -o graalvm.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${{ matrix.java }}/graalvm-community-jdk-${{ matrix.java }}_macos-x64_bin.tar.gz + tar -zxvf graalvm.tar.gz -C $JAVA_HOME --strip-components=1 + JAVA_HOME=$RUNNER_WORKSPACE/.graalvm/Contents/Home + echo $JAVA_HOME + echo "JAVA_HOME=$JAVA_HOME" >> $GITHUB_ENV + ls -lh $JAVA_HOME + mvn -v + + - name: Ubuntu Prerequisites + if: ${{ matrix.os == 'ubuntu-latest' }} + run: sudo apt-get install build-essential zlib1g-dev + + #- name: MacOS Prerequisites + # if: ${{ matrix.os == 'macOS-latest' }} + # run: xcode-select --install + + - name: Test with Spring Boot Native Latest + run: ./mvnw -V compile -Pnative native:compile -am -pl mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation + + - name: Run Native Latest + run: mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/target/mybatis-spring-boot-sample-graalvm-annotation diff --git a/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java new file mode 100644 index 00000000..24c910c4 --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java @@ -0,0 +1,138 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.spring.boot.autoconfigure; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.ibatis.reflection.TypeParameterResolver; +import org.mybatis.spring.mapper.MapperFactoryBean; +import org.mybatis.spring.mapper.MapperScannerConfigurer; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.RegisteredBean; +import org.springframework.util.ReflectionUtils; + +/** + * @since 3.0.4 + */ +class MyBatisBeanFactoryInitializationAotProcessor + implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter { + + private static final Set> EXCLUDE_CLASSES = new HashSet<>(); + + static { + EXCLUDE_CLASSES.add(MapperScannerConfigurer.class); + } + + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + String[] beanNames = beanFactory.getBeanNamesForType(MapperFactoryBean.class); + if (beanNames.length == 0) { + return null; + } + return (context, code) -> { + RuntimeHints hints = context.getRuntimeHints(); + for (String beanName : beanNames) { + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName.substring(1)); + PropertyValue mapperInterface = beanDefinition.getPropertyValues().getPropertyValue("mapperInterface"); + if (mapperInterface != null && mapperInterface.getValue() != null) { + Class mapperInterfaceType = (Class) mapperInterface.getValue(); + if (mapperInterfaceType != null) { + registerReflectionTypeIfNecessary(mapperInterfaceType, hints); + hints.proxies().registerJdkProxy(mapperInterfaceType); + registerMapperRelationships(mapperInterfaceType, hints); + } + } + } + }; + } + + @Override + public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { + return EXCLUDE_CLASSES.contains(registeredBean.getBeanClass()); + } + + private void registerMapperRelationships(Class mapperInterfaceType, RuntimeHints hints) { + Method[] methods = ReflectionUtils.getAllDeclaredMethods(mapperInterfaceType); + for (Method method : methods) { + if (method.getDeclaringClass() != Object.class) { + ReflectionUtils.makeAccessible(method); + Class returnType = MyBatisMapperTypeUtils.resolveReturnClass(mapperInterfaceType, method); + registerReflectionTypeIfNecessary(returnType, hints); + MyBatisMapperTypeUtils.resolveParameterClasses(mapperInterfaceType, method) + .forEach(x -> registerReflectionTypeIfNecessary(x, hints)); + } + } + } + + static class MyBatisMapperTypeUtils { + private MyBatisMapperTypeUtils() { + // NOP + } + + static Class resolveReturnClass(Class mapperInterface, Method method) { + Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface); + return typeToClass(resolvedReturnType, method.getReturnType()); + } + + static Set> resolveParameterClasses(Class mapperInterface, Method method) { + return Stream.of(TypeParameterResolver.resolveParamTypes(method, mapperInterface)) + .map(x -> typeToClass(x, x instanceof Class ? (Class) x : Object.class)).collect(Collectors.toSet()); + } + + private static Class typeToClass(Type src, Class fallback) { + Class result = null; + if (src instanceof Class) { + if (((Class) src).isArray()) { + result = ((Class) src).getComponentType(); + } else { + result = (Class) src; + } + } else if (src instanceof ParameterizedType parameterizedType) { + int index = (parameterizedType.getRawType() instanceof Class + && Map.class.isAssignableFrom((Class) parameterizedType.getRawType()) + && parameterizedType.getActualTypeArguments().length > 1) ? 1 : 0; + Type actualType = parameterizedType.getActualTypeArguments()[index]; + result = typeToClass(actualType, fallback); + } + if (result == null) { + result = fallback; + } + return result; + } + + } + + private void registerReflectionTypeIfNecessary(Class type, RuntimeHints hints) { + if (!type.isPrimitive() && !type.getName().startsWith("java")) { + hints.reflection().registerType(type, MemberCategory.values()); + } + } + +} diff --git a/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisMapperFactoryBeanPostProcessor.java b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisMapperFactoryBeanPostProcessor.java new file mode 100644 index 00000000..12d730a2 --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisMapperFactoryBeanPostProcessor.java @@ -0,0 +1,87 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.spring.boot.autoconfigure; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mybatis.spring.mapper.MapperFactoryBean; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.ResolvableType; +import org.springframework.util.ClassUtils; + +/** + * The {@code BeanDefinitionPostProcessor} for customizing a {@code MapperFactoryBean}. + * + * @author Stéphane Nicoll + * @author Kazuki Shimizu + * @author xuxiaowei + * + * @since 3.0.4 + */ +@Configuration +class MyBatisMapperFactoryBeanPostProcessor implements MergedBeanDefinitionPostProcessor, BeanFactoryAware { + + private static final Log LOG = LogFactory.getLog(MyBatisMapperFactoryBeanPostProcessor.class); + + private static final String MAPPER_FACTORY_BEAN = MapperFactoryBean.class.getName(); + + private ConfigurableBeanFactory beanFactory; + + @Override + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = (ConfigurableBeanFactory) beanFactory; + } + + @Override + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + if (ClassUtils.isPresent(MAPPER_FACTORY_BEAN, this.beanFactory.getBeanClassLoader())) { + resolveMapperFactoryBeanTypeIfNecessary(beanDefinition); + } + } + + private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) { + if (!beanDefinition.hasBeanClass() || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) { + return; + } + if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) { + Class mapperInterface = getMapperInterface(beanDefinition); + if (mapperInterface != null) { + // Exposes a generic type information to context for prevent early initializing + ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); + constructorArgumentValues.addGenericArgumentValue(mapperInterface); + beanDefinition.setConstructorArgumentValues(constructorArgumentValues); + beanDefinition + .setTargetType(ResolvableType.forClassWithGenerics(beanDefinition.getBeanClass(), mapperInterface)); + } + } + } + + private Class getMapperInterface(RootBeanDefinition beanDefinition) { + try { + return (Class) beanDefinition.getPropertyValues().get("mapperInterface"); + } catch (Exception e) { + LOG.debug("Fail getting mapper interface type.", e); + return null; + } + } + +} diff --git a/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/mybatis-reflection.json b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/mybatis-reflection.json new file mode 100644 index 00000000..1549e08e --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/mybatis-reflection.json @@ -0,0 +1,14 @@ +[ + { "name": "org.apache.ibatis.logging.slf4j.Slf4jImpl", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.logging.log4j2.Log4j2Impl", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.logging.log4j.Log4jImpl", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.logging.nologging.NoLoggingImpl", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.plugin.Interceptor", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.javassist.util.proxy.ProxyFactory", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "org.apache.ibatis.scripting.xmltags.XMLLanguageDriver", "methods": [{ "name": "", "parameterTypes": [] }] }, + { "name": "org.apache.ibatis.scripting.defaults.RawLanguageDriver", "methods": [{ "name": "", "parameterTypes": [] }] }, + { "name": "org.mybatis.spring.SqlSessionFactoryBean", "allDeclaredConstructors": true, "allDeclaredMethods": true }, + { "name": "java.util.ArrayList", "methods": [{ "name": "", "parameterTypes": [] }] } +] diff --git a/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/native-image.properties b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/native-image.properties new file mode 100644 index 00000000..96994bb2 --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/native-image.properties @@ -0,0 +1,17 @@ +# +# Copyright 2015-2024 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Args = -H:ReflectionConfigurationResources=${.}/mybatis-reflection.json diff --git a/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000..c319033d --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\ +org.mybatis.spring.boot.autoconfigure.MyBatisBeanFactoryInitializationAotProcessor diff --git a/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 2fad2b7c..91a4e32f 100644 --- a/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,2 +1,3 @@ org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration +org.mybatis.spring.boot.autoconfigure.MyBatisMapperFactoryBeanPostProcessor diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/LICENSE_HEADER b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/LICENSE_HEADER new file mode 100644 index 00000000..a81590a5 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/LICENSE_HEADER @@ -0,0 +1,13 @@ + Copyright ${license.git.copyrightYears} the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/format.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/format.xml new file mode 100644 index 00000000..bad5a471 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/format.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/pom.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/pom.xml new file mode 100644 index 00000000..b00677d9 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/pom.xml @@ -0,0 +1,176 @@ + + + + 4.0.0 + + org.mybatis.spring.boot + mybatis-spring-boot-samples + 3.0.4-SNAPSHOT + + mybatis-spring-boot-sample-graalvm-annotation + jar + mybatis-spring-boot-sample-graalvm-annotation + + org.mybatis.spring.boot.sample.graalvmannotation + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + test + + + + + + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + + native + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + paketobuildpacks/builder-jammy-tiny:latest + + true + + + + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-build-tools-plugin.version} + + ${project.build.outputDirectory} + 22.3 + + + + add-reachability-metadata + + add-reachability-metadata + + + + + + + + + + nativeTest + + + org.junit.platform + junit-platform-launcher + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + process-test-aot + + process-test-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-build-tools-plugin.version} + + ${project.build.outputDirectory} + 22.3 + + + + native-test + + test + + + + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/SampleAnnotationApplication.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/SampleAnnotationApplication.java new file mode 100644 index 00000000..f79a9d8d --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/SampleAnnotationApplication.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import sample.mybatis.graalvm.annotation.mapper.CityMapper; + +@SpringBootApplication +public class SampleAnnotationApplication implements CommandLineRunner { + + public static void main(String[] args) { + SpringApplication.run(SampleAnnotationApplication.class, args); + } + + private final CityMapper cityMapper; + + public SampleAnnotationApplication(CityMapper cityMapper) { + this.cityMapper = cityMapper; + } + + @Override + @SuppressWarnings("squid:S106") + public void run(String... args) { + System.out.println(this.cityMapper.findByState("CA")); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/domain/City.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/domain/City.java new file mode 100644 index 00000000..67764b59 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/domain/City.java @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation.domain; + +import java.io.Serializable; + +/** + * @author Eddú Meléndez + */ +public class City implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long id; + + private String name; + + private String state; + + private String country; + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getState() { + return this.state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCountry() { + return this.country; + } + + public void setCountry(String country) { + this.country = country; + } + + @Override + public String toString() { + return getId() + "," + getName() + "," + getState() + "," + getCountry(); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/mapper/CityMapper.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/mapper/CityMapper.java new file mode 100644 index 00000000..a6a8449c --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/java/sample/mybatis/graalvm/annotation/mapper/CityMapper.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import sample.mybatis.graalvm.annotation.domain.City; + +/** + * @author Eddú Meléndez + */ +@Mapper +public interface CityMapper { + + @Select("select id, name, state, country from city where state = #{state}") + City findByState(@Param("state") String state); + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/application.properties b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/application.properties new file mode 100644 index 00000000..2845bb39 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/application.properties @@ -0,0 +1,18 @@ +# +# Copyright 2015-2024 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +logging.level.root=WARN +logging.level.sample.mybatis.graalvm.annotation.mapper=TRACE diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/data.sql b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/data.sql new file mode 100644 index 00000000..12ddae3b --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/data.sql @@ -0,0 +1,17 @@ +-- +-- Copyright 2015-2024 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- https://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +insert into city (name, state, country) values ('San Francisco', 'CA', 'US'); diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/schema.sql b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/schema.sql new file mode 100644 index 00000000..b3e263bb --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/schema.sql @@ -0,0 +1,20 @@ +-- +-- Copyright 2015-2024 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- https://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +drop table if exists city; + +create table city (id int primary key auto_increment, name varchar, state varchar, country varchar); + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/extensions/annotation/CaptureSystemOutput.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/extensions/annotation/CaptureSystemOutput.java new file mode 100644 index 00000000..44c15a26 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/extensions/annotation/CaptureSystemOutput.java @@ -0,0 +1,255 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package extensions.annotation; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.List; + +import org.hamcrest.Matcher; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.platform.commons.support.ReflectionSupport; + +/** + * {@code @CaptureSystemOutput} is a JUnit JUpiter extension for capturing output to {@code System.out} and + * {@code System.err} with expectations supported via Hamcrest matchers. + *

Example Usage

+ * + *
+ * {@literal @}Test
+ * {@literal @}CaptureSystemOutput
+ * void systemOut(OutputCapture outputCapture) {
+ *     outputCapture.expect(containsString("System.out!"));
+ *
+ *     System.out.println("Printed to System.out!");
+ * }
+ *
+ * {@literal @}Test
+ * {@literal @}CaptureSystemOutput
+ * void systemErr(OutputCapture outputCapture) {
+ *     outputCapture.expect(containsString("System.err!"));
+ *
+ *     System.err.println("Printed to System.err!");
+ * }
+ * 
+ *

+ * Based on code from Spring Boot's OutputCapture + * rule for JUnit 4 by Phillip Webb and Andy Wilkinson. + *

+ * Borrowing source from Sam Brannen as listed online at spring and stackoverflow from here CaptureSystemOutput + *

+ * Additional changes to Sam Brannen logic supplied by kazuki43zoo from here enhancement + * capture + * + * @author Sam Brannen + * @author Phillip Webb + * @author Andy Wilkinson + */ +@Target({ TYPE, METHOD }) +@Retention(RUNTIME) +@ExtendWith(CaptureSystemOutput.Extension.class) +public @interface CaptureSystemOutput { + + class Extension implements BeforeAllCallback, AfterAllCallback, AfterEachCallback, ParameterResolver { + + @Override + public void beforeAll(ExtensionContext context) { + getOutputCapture(context).captureOutput(); + } + + public void afterAll(ExtensionContext context) { + getOutputCapture(context).releaseOutput(); + } + + @Override + public void afterEach(ExtensionContext context) { + OutputCapture outputCapture = getOutputCapture(context); + try { + if (!outputCapture.matchers.isEmpty()) { + String output = outputCapture.toString(); + assertThat(output, allOf(outputCapture.matchers)); + } + } finally { + outputCapture.reset(); + } + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + boolean isTestMethodLevel = extensionContext.getTestMethod().isPresent(); + boolean isOutputCapture = parameterContext.getParameter().getType() == OutputCapture.class; + return isTestMethodLevel && isOutputCapture; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return getOutputCapture(extensionContext); + } + + private OutputCapture getOutputCapture(ExtensionContext context) { + return getOrComputeIfAbsent(getStore(context), OutputCapture.class); + } + + private V getOrComputeIfAbsent(Store store, Class type) { + return store.getOrComputeIfAbsent(type, ReflectionSupport::newInstance, type); + } + + private Store getStore(ExtensionContext context) { + return context.getStore(Namespace.create(getClass())); + } + + } + + /** + * {@code OutputCapture} captures output to {@code System.out} and {@code System.err}. + *

+ * To obtain an instance of {@code OutputCapture}, declare a parameter of type {@code OutputCapture} in a JUnit + * Jupiter {@code @Test}, {@code @BeforeEach}, or {@code @AfterEach} method. + *

+ * {@linkplain #expect Expectations} are supported via Hamcrest matchers. + *

+ * To obtain all output to {@code System.out} and {@code System.err}, simply invoke {@link #toString()}. + * + * @author Phillip Webb + * @author Andy Wilkinson + * @author Sam Brannen + */ + static class OutputCapture { + + private final List> matchers = new ArrayList<>(); + + private CaptureOutputStream captureOut; + + private CaptureOutputStream captureErr; + + private ByteArrayOutputStream copy; + + void captureOutput() { + this.copy = new ByteArrayOutputStream(); + this.captureOut = new CaptureOutputStream(System.out, this.copy); + this.captureErr = new CaptureOutputStream(System.err, this.copy); + System.setOut(new PrintStream(this.captureOut)); + System.setErr(new PrintStream(this.captureErr)); + } + + void releaseOutput() { + System.setOut(this.captureOut.getOriginal()); + System.setErr(this.captureErr.getOriginal()); + this.copy = null; + } + + private void flush() { + try { + this.captureOut.flush(); + this.captureErr.flush(); + } catch (IOException ex) { + // ignore + } + } + + /** + * Verify that the captured output is matched by the supplied {@code matcher}. + *

+ * Verification is performed after the test method has executed. + * + * @param matcher + * the matcher + */ + public void expect(Matcher matcher) { + this.matchers.add(matcher); + } + + /** + * Return all captured output to {@code System.out} and {@code System.err} as a single string. + */ + @Override + public String toString() { + flush(); + return this.copy.toString(); + } + + void reset() { + this.matchers.clear(); + this.copy.reset(); + } + + private static class CaptureOutputStream extends OutputStream { + + private final PrintStream original; + + private final OutputStream copy; + + CaptureOutputStream(PrintStream original, OutputStream copy) { + this.original = original; + this.copy = copy; + } + + PrintStream getOriginal() { + return this.original; + } + + @Override + public void write(int b) throws IOException { + this.copy.write(b); + this.original.write(b); + this.original.flush(); + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + this.copy.write(b, off, len); + this.original.write(b, off, len); + } + + @Override + public void flush() throws IOException { + this.copy.flush(); + this.original.flush(); + } + + } + + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationMainTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationMainTest.java new file mode 100644 index 00000000..5ccbf28c --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationMainTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import extensions.annotation.CaptureSystemOutput; +import extensions.annotation.CaptureSystemOutput.OutputCapture; + +/** + * @author Kazuki Shimizu + */ +@CaptureSystemOutput +class SampleMybatisApplicationMainTest { + + @Test + void test(OutputCapture outputCapture) { + SampleAnnotationApplication.main(new String[] {}); + String output = outputCapture.toString(); + assertThat(output).contains("1,San Francisco,CA,US"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationTest.java new file mode 100644 index 00000000..8b10b8db --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/SampleMybatisApplicationTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import extensions.annotation.CaptureSystemOutput; +import extensions.annotation.CaptureSystemOutput.OutputCapture; + +/** + * @author Eddú Meléndez + * @author Kazuki Shimizu + */ +@CaptureSystemOutput +@SpringBootTest +class SampleMybatisApplicationTest { + + @Test + void test(OutputCapture outputCapture) { + String output = outputCapture.toString(); + assertThat(output).contains("1,San Francisco,CA,US"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/CityMapperTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/CityMapperTest.java new file mode 100644 index 00000000..209ec6fc --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/CityMapperTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; +import org.springframework.beans.factory.annotation.Autowired; + +import sample.mybatis.graalvm.annotation.domain.City; + +/** + * Tests for {@link CityMapper}. + * + * @author wonwoo + * + * @since 1.2.1 + */ +@MybatisTest +class CityMapperTest { + + @Autowired + private CityMapper cityMapper; + + @Test + void findByStateTest() { + City city = cityMapper.findByState("CA"); + assertThat(city.getId()).isEqualTo(1); + assertThat(city.getName()).isEqualTo("San Francisco"); + assertThat(city.getState()).isEqualTo("CA"); + assertThat(city.getCountry()).isEqualTo("US"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/MapperTestApplication.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/MapperTestApplication.java new file mode 100644 index 00000000..13f8768c --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/test/java/sample/mybatis/graalvm/annotation/mapper/MapperTestApplication.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.annotation.mapper; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * The Spring Boot Application for testing {@link org.mybatis.spring.boot.test.autoconfigure.MybatisTest @MybatisTest}. + *

+ * This class has role for prevent to run the {@link sample.mybatis.graalvm.annotation.SampleAnnotationApplication}. For + * more detail information, please refer + * Here. + * + * @author Kazuki Shimizu + * + * @since 1.2.1 + */ +@SpringBootApplication +public class MapperTestApplication { + +} diff --git a/mybatis-spring-boot-samples/pom.xml b/mybatis-spring-boot-samples/pom.xml index 14a9ab91..f19c2be6 100644 --- a/mybatis-spring-boot-samples/pom.xml +++ b/mybatis-spring-boot-samples/pom.xml @@ -1,7 +1,7 @@ + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/pom.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/pom.xml new file mode 100644 index 00000000..02dcb64d --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/pom.xml @@ -0,0 +1,176 @@ + + + + 4.0.0 + + org.mybatis.spring.boot + mybatis-spring-boot-samples + 3.0.4-SNAPSHOT + + mybatis-spring-boot-sample-graalvm-xml + jar + mybatis-spring-boot-sample-graalvm-xml + + org.mybatis.spring.boot.sample.graalvmxml + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + test + + + + + + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + + native + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + paketobuildpacks/builder-jammy-tiny:latest + + true + + + + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-build-tools-plugin.version} + + ${project.build.outputDirectory} + 22.3 + + + + add-reachability-metadata + + add-reachability-metadata + + + + + + + + + + nativeTest + + + org.junit.platform + junit-platform-launcher + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + process-test-aot + + process-test-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-build-tools-plugin.version} + + ${project.build.outputDirectory} + 22.3 + + + + native-test + + test + + + + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/SampleXmlApplication.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/SampleXmlApplication.java new file mode 100644 index 00000000..daf59b61 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/SampleXmlApplication.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import sample.mybatis.graalvm.xml.dao.CityDao; +import sample.mybatis.graalvm.xml.mapper.CityMapper; +import sample.mybatis.graalvm.xml.mapper.HotelMapper; + +@SpringBootApplication +public class SampleXmlApplication implements CommandLineRunner { + + public static void main(String[] args) { + SpringApplication.run(SampleXmlApplication.class, args); + } + + private final CityDao cityDao; + + private final CityMapper cityMapper; + + private final HotelMapper hotelMapper; + + public SampleXmlApplication(CityDao cityDao, CityMapper cityMapper, HotelMapper hotelMapper) { + this.cityDao = cityDao; + this.cityMapper = cityMapper; + this.hotelMapper = hotelMapper; + } + + @Override + @SuppressWarnings("squid:S106") + public void run(String... args) { + System.out.println(this.cityDao.selectCityById(1)); + System.out.println(this.cityMapper.findByState("CA")); + System.out.println(this.cityMapper.listByState("ShanDong")); + System.out.println(this.cityMapper.mapByState("CA")); + System.out.println(this.cityMapper.listMapByState("ShanDong")); + System.out.println(this.cityMapper.treeSetStateByState("CN")); + System.out.println(this.cityMapper.hashSetStateByState("CN")); + System.out.println(this.hotelMapper.selectByCityId(1)); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/dao/CityDao.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/dao/CityDao.java new file mode 100644 index 00000000..eab35b24 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/dao/CityDao.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.dao; + +import org.apache.ibatis.session.SqlSession; +import org.springframework.stereotype.Component; + +import sample.mybatis.graalvm.xml.domain.City; + +/** + * @author Eddú Meléndez + */ +@Component +public class CityDao { + + private final SqlSession sqlSession; + + public CityDao(SqlSession sqlSession) { + this.sqlSession = sqlSession; + } + + public City selectCityById(long id) { + return this.sqlSession.selectOne("selectCityById", id); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/domain/City.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/domain/City.java new file mode 100644 index 00000000..cfaf35c4 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/domain/City.java @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.domain; + +import java.io.Serializable; + +/** + * @author Eddú Meléndez + */ +public class City implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long id; + + private String name; + + private String state; + + private String country; + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getState() { + return this.state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCountry() { + return this.country; + } + + public void setCountry(String country) { + this.country = country; + } + + @Override + public String toString() { + return getId() + "," + getName() + "," + getState() + "," + getCountry(); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/domain/Hotel.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/domain/Hotel.java new file mode 100644 index 00000000..873c7239 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/domain/Hotel.java @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Eduardo Macarron + */ +package sample.mybatis.graalvm.xml.domain; + +import java.io.Serializable; + +public class Hotel implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long city; + + private String name; + + private String address; + + private String zip; + + public Long getCity() { + return city; + } + + public void setCity(Long city) { + this.city = city; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } + + @Override + public String toString() { + return getCity() + "," + getName() + "," + getAddress() + "," + getZip(); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java new file mode 100644 index 00000000..5f7eb173 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import sample.mybatis.graalvm.xml.domain.City; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; + +/** + * @author Eddú Meléndez + */ +@Mapper +public interface CityMapper { + + City findByState(@Param("state") String state); + + List listByState(@Param("state") String state); + + Map mapByState(@Param("state") String state); + + List> listMapByState(@Param("state") String state); + + TreeSet treeSetStateByState(@Param("country") String country); + + HashSet hashSetStateByState(@Param("country") String country); + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/HotelMapper.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/HotelMapper.java new file mode 100644 index 00000000..2b2fa3a9 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/HotelMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.mapper; + +import org.apache.ibatis.annotations.Mapper; + +import sample.mybatis.graalvm.xml.domain.Hotel; + +/** + * @author Eduardo Macarron + */ +@Mapper +public interface HotelMapper { + + Hotel selectByCityId(int cityId); + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 00000000..7e262155 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,9 @@ +{ + "resources": { + "includes": [ + { "pattern": "mybatis-config.xml" }, + { "pattern": "sample/mybatis/graalvm/xml/mapper/CityMapper.xml" }, + { "pattern": "sample/mybatis/graalvm/xml/mapper/HotelMapper.xml" } + ] + } +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties new file mode 100644 index 00000000..3673a470 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties @@ -0,0 +1,19 @@ +# +# Copyright 2015-2024 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +mybatis.config-location=classpath:mybatis-config.xml +logging.level.root=WARN +logging.level.sample.mybatis.graalvm.xml.mapper=TRACE diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/data.sql b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/data.sql new file mode 100644 index 00000000..16e36ecf --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/data.sql @@ -0,0 +1,20 @@ +-- +-- Copyright 2015-2024 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- https://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +insert into city (name, state, country) values ('San Francisco', 'CA', 'US'); +insert into city (name, state, country) values ('Jinan', 'ShanDong', 'CN'); +insert into city (name, state, country) values ('Tsingtao', 'ShanDong', 'CN'); +insert into hotel(city, name, address, zip) values (1, 'Conrad Treasury Place', 'William & George Streets', '4001') diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml new file mode 100644 index 00000000..482f7086 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/CityMapper.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/CityMapper.xml new file mode 100644 index 00000000..25ab2295 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/CityMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/HotelMapper.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/HotelMapper.xml new file mode 100644 index 00000000..6ea0cb13 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/HotelMapper.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/schema.sql b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/schema.sql new file mode 100644 index 00000000..34e24c72 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/schema.sql @@ -0,0 +1,21 @@ +-- +-- Copyright 2015-2024 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- https://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +drop table if exists city; +drop table if exists hotel; + +create table city (id int primary key auto_increment, name varchar, state varchar, country varchar); +create table hotel (city int, name varchar, address varchar, zip varchar); diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/extensions/xml/CaptureSystemOutput.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/extensions/xml/CaptureSystemOutput.java new file mode 100644 index 00000000..6e91d18c --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/extensions/xml/CaptureSystemOutput.java @@ -0,0 +1,255 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package extensions.xml; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.List; + +import org.hamcrest.Matcher; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.platform.commons.support.ReflectionSupport; + +/** + * {@code @CaptureSystemOutput} is a JUnit JUpiter extension for capturing output to {@code System.out} and + * {@code System.err} with expectations supported via Hamcrest matchers. + *

Example Usage

+ * + *
+ * {@literal @}Test
+ * {@literal @}CaptureSystemOutput
+ * void systemOut(OutputCapture outputCapture) {
+ *     outputCapture.expect(containsString("System.out!"));
+ *
+ *     System.out.println("Printed to System.out!");
+ * }
+ *
+ * {@literal @}Test
+ * {@literal @}CaptureSystemOutput
+ * void systemErr(OutputCapture outputCapture) {
+ *     outputCapture.expect(containsString("System.err!"));
+ *
+ *     System.err.println("Printed to System.err!");
+ * }
+ * 
+ *

+ * Based on code from Spring Boot's OutputCapture + * rule for JUnit 4 by Phillip Webb and Andy Wilkinson. + *

+ * Borrowing source from Sam Brannen as listed online at spring and stackoverflow from here CaptureSystemOutput + *

+ * Additional changes to Sam Brannen logic supplied by kazuki43zoo from here enhancement + * capture + * + * @author Sam Brannen + * @author Phillip Webb + * @author Andy Wilkinson + */ +@Target({ TYPE, METHOD }) +@Retention(RUNTIME) +@ExtendWith(CaptureSystemOutput.Extension.class) +public @interface CaptureSystemOutput { + + class Extension implements BeforeAllCallback, AfterAllCallback, AfterEachCallback, ParameterResolver { + + @Override + public void beforeAll(ExtensionContext context) { + getOutputCapture(context).captureOutput(); + } + + public void afterAll(ExtensionContext context) { + getOutputCapture(context).releaseOutput(); + } + + @Override + public void afterEach(ExtensionContext context) { + OutputCapture outputCapture = getOutputCapture(context); + try { + if (!outputCapture.matchers.isEmpty()) { + String output = outputCapture.toString(); + assertThat(output, allOf(outputCapture.matchers)); + } + } finally { + outputCapture.reset(); + } + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + boolean isTestMethodLevel = extensionContext.getTestMethod().isPresent(); + boolean isOutputCapture = parameterContext.getParameter().getType() == OutputCapture.class; + return isTestMethodLevel && isOutputCapture; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return getOutputCapture(extensionContext); + } + + private OutputCapture getOutputCapture(ExtensionContext context) { + return getOrComputeIfAbsent(getStore(context), OutputCapture.class); + } + + private V getOrComputeIfAbsent(Store store, Class type) { + return store.getOrComputeIfAbsent(type, ReflectionSupport::newInstance, type); + } + + private Store getStore(ExtensionContext context) { + return context.getStore(Namespace.create(getClass())); + } + + } + + /** + * {@code OutputCapture} captures output to {@code System.out} and {@code System.err}. + *

+ * To obtain an instance of {@code OutputCapture}, declare a parameter of type {@code OutputCapture} in a JUnit + * Jupiter {@code @Test}, {@code @BeforeEach}, or {@code @AfterEach} method. + *

+ * {@linkplain #expect Expectations} are supported via Hamcrest matchers. + *

+ * To obtain all output to {@code System.out} and {@code System.err}, simply invoke {@link #toString()}. + * + * @author Phillip Webb + * @author Andy Wilkinson + * @author Sam Brannen + */ + static class OutputCapture { + + private final List> matchers = new ArrayList<>(); + + private CaptureOutputStream captureOut; + + private CaptureOutputStream captureErr; + + private ByteArrayOutputStream copy; + + void captureOutput() { + this.copy = new ByteArrayOutputStream(); + this.captureOut = new CaptureOutputStream(System.out, this.copy); + this.captureErr = new CaptureOutputStream(System.err, this.copy); + System.setOut(new PrintStream(this.captureOut)); + System.setErr(new PrintStream(this.captureErr)); + } + + void releaseOutput() { + System.setOut(this.captureOut.getOriginal()); + System.setErr(this.captureErr.getOriginal()); + this.copy = null; + } + + private void flush() { + try { + this.captureOut.flush(); + this.captureErr.flush(); + } catch (IOException ex) { + // ignore + } + } + + /** + * Verify that the captured output is matched by the supplied {@code matcher}. + *

+ * Verification is performed after the test method has executed. + * + * @param matcher + * the matcher + */ + public void expect(Matcher matcher) { + this.matchers.add(matcher); + } + + /** + * Return all captured output to {@code System.out} and {@code System.err} as a single string. + */ + @Override + public String toString() { + flush(); + return this.copy.toString(); + } + + void reset() { + this.matchers.clear(); + this.copy.reset(); + } + + private static class CaptureOutputStream extends OutputStream { + + private final PrintStream original; + + private final OutputStream copy; + + CaptureOutputStream(PrintStream original, OutputStream copy) { + this.original = original; + this.copy = copy; + } + + PrintStream getOriginal() { + return this.original; + } + + @Override + public void write(int b) throws IOException { + this.copy.write(b); + this.original.write(b); + this.original.flush(); + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + this.copy.write(b, off, len); + this.original.write(b, off, len); + } + + @Override + public void flush() throws IOException { + this.copy.flush(); + this.original.flush(); + } + + } + + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/SampleMybatisApplicationMainTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/SampleMybatisApplicationMainTest.java new file mode 100644 index 00000000..b46c7609 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/SampleMybatisApplicationMainTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import extensions.xml.CaptureSystemOutput; +import extensions.xml.CaptureSystemOutput.OutputCapture; + +/** + * @author Kazuki Shimizu + */ +@CaptureSystemOutput +class SampleMybatisApplicationMainTest { + + @Test + void test(OutputCapture outputCapture) { + SampleXmlApplication.main(new String[] {}); + String output = outputCapture.toString(); + assertThat(output).contains("1,San Francisco,CA,US"); + assertThat(output).contains("2,Jinan,ShanDong,CN"); + assertThat(output).contains("3,Tsingtao,ShanDong,CN"); + assertThat(output).contains("{COUNTRY=CN, STATE=ShanDong, ID=2, NAME=Jinan}"); + assertThat(output).contains("{COUNTRY=CN, STATE=ShanDong, ID=3, NAME=Tsingtao}"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/SampleMybatisApplicationTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/SampleMybatisApplicationTest.java new file mode 100644 index 00000000..5be3c246 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/SampleMybatisApplicationTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import extensions.xml.CaptureSystemOutput; +import extensions.xml.CaptureSystemOutput.OutputCapture; + +/** + * @author Eddú Meléndez + * @author Kazuki Shimizu + */ +@CaptureSystemOutput +@SpringBootTest +class SampleMybatisApplicationTest { + + @Test + void test(OutputCapture outputCapture) { + String output = outputCapture.toString(); + assertThat(output).contains("1,San Francisco,CA,US"); + assertThat(output).contains("2,Jinan,ShanDong,CN"); + assertThat(output).contains("3,Tsingtao,ShanDong,CN"); + assertThat(output).contains("{COUNTRY=CN, STATE=ShanDong, ID=2, NAME=Jinan}"); + assertThat(output).contains("{COUNTRY=CN, STATE=ShanDong, ID=3, NAME=Tsingtao}"); + assertThat(output).contains("1,Conrad Treasury Place,William & George Streets,4001"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/dao/CityDaoTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/dao/CityDaoTest.java new file mode 100644 index 00000000..ee988fe6 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/dao/CityDaoTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.dao; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; + +import sample.mybatis.graalvm.xml.domain.City; + +/** + * Tests for {@link CityDao}. + * + * @author wonwoo + * + * @since 1.2.1 + */ +@MybatisTest +@Import(CityDao.class) +class CityDaoTest { + + @Autowired + private CityDao cityDao; + + @Test + void selectCityByIdTest() { + City city = cityDao.selectCityById(1); + assertThat(city.getId()).isEqualTo(1); + assertThat(city.getName()).isEqualTo("San Francisco"); + assertThat(city.getState()).isEqualTo("CA"); + assertThat(city.getCountry()).isEqualTo("US"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/dao/DaoTestApplication.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/dao/DaoTestApplication.java new file mode 100644 index 00000000..35c0466f --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/dao/DaoTestApplication.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.dao; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * The Spring Boot Application for testing {@link org.mybatis.spring.boot.test.autoconfigure.MybatisTest @MybatisTest}. + *

+ * This class has role for prevent to run the {@link sample.mybatis.graalvm.xml.SampleXmlApplication}. For more detail + * information, please refer + * Here. + * + * @author Kazuki Shimizu + * + * @since 1.2.1 + */ +@SpringBootApplication +public class DaoTestApplication { + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/CityMapperTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/CityMapperTest.java new file mode 100644 index 00000000..75563e94 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/CityMapperTest.java @@ -0,0 +1,114 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.mapper; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; + +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; +import org.springframework.beans.factory.annotation.Autowired; + +import sample.mybatis.graalvm.xml.domain.City; + +/** + * Tests for {@link CityMapper}. + * + * @author wonwoo + * + * @since 1.2.1 + */ +@MybatisTest +class CityMapperTest { + + @Autowired + private CityMapper cityMapper; + + @Test + void findByStateTest() { + City city = cityMapper.findByState("CA"); + assertThat(city.getId()).isEqualTo(1); + assertThat(city.getName()).isEqualTo("San Francisco"); + assertThat(city.getState()).isEqualTo("CA"); + assertThat(city.getCountry()).isEqualTo("US"); + } + + @Test + void listByStateTest() { + List cityList = cityMapper.listByState("ShanDong"); + assertThat(cityList).isNotNull(); + assertThat(cityList.size()).isEqualTo(2); + + assertThat(cityList).satisfies(cities -> { + assertThat(cities).filteredOn(city -> city.getId() == 2 && "Jinan".equals(city.getName()) + && "ShanDong".equals(city.getState()) && "CN".equals(city.getCountry())).hasSize(1); + assertThat(cities).filteredOn(city -> city.getId() == 3 && "Tsingtao".equals(city.getName()) + && "ShanDong".equals(city.getState()) && "CN".equals(city.getCountry())).hasSize(1); + }); + } + + @Test + void mapByStateTest() { + Map map = cityMapper.mapByState("CA"); + assertThat(map).isNotNull(); + assertThat(map.size()).isEqualTo(4); + assertThat(map).satisfies(cities -> { + assertThat(cities) + .contains(entry("ID", 1), entry("NAME", "San Francisco"), entry("STATE", "CA"), entry("COUNTRY", "US")) + .isNotNull(); + }); + } + + @Test + void listMapByStateTest() { + List> cityList = cityMapper.listMapByState("ShanDong"); + assertThat(cityList).isNotNull(); + assertThat(cityList).satisfies(map -> { + assertThat(map).isNotNull(); + assertThat(map.size()).isEqualTo(2); + assertThat(map).satisfies(cities -> { + assertThat(cities).filteredOn(city -> city.size() == 4 && city.get("ID") instanceof Integer + && (Integer) city.get("ID") == 2 && "Jinan".equals(city.get("NAME")) && "ShanDong".equals(city.get("STATE")) + && "CN".equals(city.get("COUNTRY"))).hasSize(1); + assertThat(cities).filteredOn(city -> city.size() == 4 && city.get("ID") instanceof Integer + && (Integer) city.get("ID") == 3 && "Tsingtao".equals(city.get("NAME")) + && "ShanDong".equals(city.get("STATE")) && "CN".equals(city.get("COUNTRY"))).hasSize(1); + }); + }); + } + + @Test + void treeSetStateByStateTest() { + TreeSet stateSet = cityMapper.treeSetStateByState("CN"); + assertThat(stateSet).isNotNull(); + assertThat(stateSet.size()).isEqualTo(1); + assertThat(stateSet.first()).isEqualTo("ShanDong"); + } + + @Test + void hashSetStateByStateTest() { + HashSet stateSet = cityMapper.hashSetStateByState("CN"); + assertThat(stateSet).isNotNull(); + assertThat(stateSet.size()).isEqualTo(1); + assertThat(stateSet).contains("ShanDong"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/HotelMapperTest.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/HotelMapperTest.java new file mode 100644 index 00000000..63357708 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/HotelMapperTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; +import org.springframework.beans.factory.annotation.Autowired; + +import sample.mybatis.graalvm.xml.domain.Hotel; + +/** + * Tests for {@link HotelMapper}. + * + * @author wonwoo + * + * @since 1.2.1 + */ +@MybatisTest +class HotelMapperTest { + + @Autowired + private HotelMapper hotelMapper; + + @Test + void selectByCityIdTest() { + Hotel hotel = hotelMapper.selectByCityId(1); + assertThat(hotel.getCity()).isEqualTo(1); + assertThat(hotel.getName()).isEqualTo("Conrad Treasury Place"); + assertThat(hotel.getAddress()).isEqualTo("William & George Streets"); + assertThat(hotel.getZip()).isEqualTo("4001"); + } + +} diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/MapperTestApplication.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/MapperTestApplication.java new file mode 100644 index 00000000..82416a08 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/test/java/sample/mybatis/graalvm/xml/mapper/MapperTestApplication.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.mybatis.graalvm.xml.mapper; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * The Spring Boot Application for testing {@link org.mybatis.spring.boot.test.autoconfigure.MybatisTest @MybatisTest}. + *

+ * This class has role for prevent to run the {@link sample.mybatis.graalvm.xml.SampleXmlApplication}. For more detail + * information, please refer + * Here. + * + * @author Kazuki Shimizu + * + * @since 1.2.1 + */ +@SpringBootApplication +public class MapperTestApplication { + +} diff --git a/mybatis-spring-boot-samples/pom.xml b/mybatis-spring-boot-samples/pom.xml index f19c2be6..52888f03 100644 --- a/mybatis-spring-boot-samples/pom.xml +++ b/mybatis-spring-boot-samples/pom.xml @@ -31,6 +31,7 @@ mybatis-spring-boot-sample-freemarker mybatis-spring-boot-sample-freemarker-legacy mybatis-spring-boot-sample-graalvm-annotation + mybatis-spring-boot-sample-graalvm-xml mybatis-spring-boot-sample-groovy mybatis-spring-boot-sample-kotlin mybatis-spring-boot-sample-thymeleaf From fb1629f8d37759db73e2a4a74a2c87ea4e828316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Thu, 8 Aug 2024 17:36:37 +0800 Subject: [PATCH 09/13] :art: format code --- .../graalvm/xml/mapper/CityMapper.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java index 5f7eb173..6ac8f2b5 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/java/sample/mybatis/graalvm/xml/mapper/CityMapper.java @@ -15,32 +15,32 @@ */ package sample.mybatis.graalvm.xml.mapper; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import sample.mybatis.graalvm.xml.domain.City; - import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.TreeSet; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import sample.mybatis.graalvm.xml.domain.City; + /** * @author Eddú Meléndez */ @Mapper public interface CityMapper { - City findByState(@Param("state") String state); + City findByState(@Param("state") String state); - List listByState(@Param("state") String state); + List listByState(@Param("state") String state); - Map mapByState(@Param("state") String state); + Map mapByState(@Param("state") String state); - List> listMapByState(@Param("state") String state); + List> listMapByState(@Param("state") String state); - TreeSet treeSetStateByState(@Param("country") String country); + TreeSet treeSetStateByState(@Param("country") String country); - HashSet hashSetStateByState(@Param("country") String country); + HashSet hashSetStateByState(@Param("country") String country); } From 5ef758c5337772f014581d757b9ac6390562c87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Thu, 8 Aug 2024 17:37:40 +0800 Subject: [PATCH 10/13] :construction_worker: add cache --- .github/workflows/native.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 0d2e88f7..2a209d35 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -58,6 +58,13 @@ jobs: ls -lh $JAVA_HOME mvn -v + - name: Cache modules + uses: actions/cache@v4 + with: + path: | + ~/.m2/repository + key: ${{ runner.os }}-${{ matrix.java }} + - name: Ubuntu Prerequisites if: ${{ matrix.os == 'ubuntu-latest' }} run: sudo apt-get install build-essential zlib1g-dev From c17619ac1901e48ea8eb76126a36a94bd5a891b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Thu, 8 Aug 2024 23:22:26 +0800 Subject: [PATCH 11/13] :bug: Native Support mybatis.config-location https://github.com/mybatis/spring-boot-starter/issues/994 --- .github/workflows/native.yaml | 2 +- ...BeanFactoryInitializationAotProcessor.java | 31 +++++++++++++++++++ .../native-image/resource-config.json | 1 - 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 2a209d35..183cb869 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -74,7 +74,7 @@ jobs: # run: xcode-select --install - name: Test with Spring Boot Native Latest - run: ./mvnw -V compile -Pnative native:compile -am -pl mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation,mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml + run: ./mvnw -V clean compile -Pnative native:compile -am -pl mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation,mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml - name: Run Native Latest run: | diff --git a/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java index 24c910c4..4ec291d0 100644 --- a/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java +++ b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java @@ -27,6 +27,8 @@ import org.apache.ibatis.reflection.TypeParameterResolver; import org.mybatis.spring.mapper.MapperFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.beans.PropertyValue; @@ -36,7 +38,13 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.RegisteredBean; +import org.springframework.core.env.Environment; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.util.ReflectionUtils; +import org.springframework.util.ResourceUtils; +import org.springframework.util.StringUtils; /** * @since 3.0.4 @@ -44,6 +52,12 @@ class MyBatisBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter { + private static final Logger logger = LoggerFactory.getLogger(MyBatisBeanFactoryInitializationAotProcessor.class); + + private static final ResourceLoader RESOURCE_RESOLVER = new PathMatchingResourcePatternResolver(); + + private static final String CONFIG_LOCATION = MybatisProperties.MYBATIS_PREFIX + ".config-location"; + private static final Set> EXCLUDE_CLASSES = new HashSet<>(); static { @@ -58,6 +72,10 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL } return (context, code) -> { RuntimeHints hints = context.getRuntimeHints(); + + Environment environment = beanFactory.getBean(Environment.class); + configLocation(environment, hints); + for (String beanName : beanNames) { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName.substring(1)); PropertyValue mapperInterface = beanDefinition.getPropertyValues().getPropertyValue("mapperInterface"); @@ -78,6 +96,19 @@ public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { return EXCLUDE_CLASSES.contains(registeredBean.getBeanClass()); } + private void configLocation(Environment environment, RuntimeHints hints) { + String configLocation = environment.getProperty(CONFIG_LOCATION); + if (StringUtils.hasText(configLocation)) { + Resource resource = RESOURCE_RESOLVER.getResource(configLocation); + if (resource.exists()) { + Stream.of(configLocation.replace(ResourceUtils.CLASSPATH_URL_PREFIX, "")) + .forEach(hints.resources()::registerPattern); + } else { + logger.error("{}: {} does not exist", CONFIG_LOCATION, configLocation); + } + } + } + private void registerMapperRelationships(Class mapperInterfaceType, RuntimeHints hints) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(mapperInterfaceType); for (Method method : methods) { diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json index 7e262155..d5027229 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json @@ -1,7 +1,6 @@ { "resources": { "includes": [ - { "pattern": "mybatis-config.xml" }, { "pattern": "sample/mybatis/graalvm/xml/mapper/CityMapper.xml" }, { "pattern": "sample/mybatis/graalvm/xml/mapper/HotelMapper.xml" } ] From 321ad4598c31ee8fe5c20dff89feef59ce3d6ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Fri, 9 Aug 2024 09:57:55 +0800 Subject: [PATCH 12/13] :bug: Native Support mybatis.mapper-locations optimize mybatis.config-location https://github.com/mybatis/spring-boot-starter/issues/994 --- ...tisBeanFactoryInitializationAotProcessor.java | 16 ++++++++++++++-- .../META-INF/native-image/resource-config.json | 3 +-- .../src/main/resources/application.properties | 1 + .../src/main/resources/mybatis-config.xml | 1 - .../xml/{mapper => custommapper}/HotelMapper.xml | 0 5 files changed, 16 insertions(+), 5 deletions(-) rename mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/{mapper => custommapper}/HotelMapper.xml (100%) diff --git a/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java index 4ec291d0..74d241c6 100644 --- a/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java +++ b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java @@ -58,6 +58,8 @@ class MyBatisBeanFactoryInitializationAotProcessor private static final String CONFIG_LOCATION = MybatisProperties.MYBATIS_PREFIX + ".config-location"; + private static final String MAPPER_LOCATIONS = MybatisProperties.MYBATIS_PREFIX + ".mapper-locations"; + private static final Set> EXCLUDE_CLASSES = new HashSet<>(); static { @@ -75,6 +77,7 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL Environment environment = beanFactory.getBean(Environment.class); configLocation(environment, hints); + mapperLocations(environment, hints); for (String beanName : beanNames) { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName.substring(1)); @@ -101,14 +104,23 @@ private void configLocation(Environment environment, RuntimeHints hints) { if (StringUtils.hasText(configLocation)) { Resource resource = RESOURCE_RESOLVER.getResource(configLocation); if (resource.exists()) { - Stream.of(configLocation.replace(ResourceUtils.CLASSPATH_URL_PREFIX, "")) - .forEach(hints.resources()::registerPattern); + Stream.of(resource).forEach(hints.resources()::registerResource); } else { logger.error("{}: {} does not exist", CONFIG_LOCATION, configLocation); } } } + private void mapperLocations(Environment environment, RuntimeHints hints) { + String[] mapperLocations = environment.getProperty(MAPPER_LOCATIONS, String[].class); + if (mapperLocations != null) { + for (String mapperLocation : mapperLocations) { + Stream.of(mapperLocation.replace(ResourceUtils.CLASSPATH_URL_PREFIX, "")) + .forEach(hints.resources()::registerPattern); + } + } + } + private void registerMapperRelationships(Class mapperInterfaceType, RuntimeHints hints) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(mapperInterfaceType); for (Method method : methods) { diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json index d5027229..0f33d9bb 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/META-INF/native-image/resource-config.json @@ -1,8 +1,7 @@ { "resources": { "includes": [ - { "pattern": "sample/mybatis/graalvm/xml/mapper/CityMapper.xml" }, - { "pattern": "sample/mybatis/graalvm/xml/mapper/HotelMapper.xml" } + { "pattern": "sample/mybatis/graalvm/xml/mapper/CityMapper.xml" } ] } } diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties index 3673a470..e660f5f3 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties @@ -15,5 +15,6 @@ # mybatis.config-location=classpath:mybatis-config.xml +mybatis.mapper-locations=classpath:sample/mybatis/graalvm/xml/custommapper/*.xml logging.level.root=WARN logging.level.sample.mybatis.graalvm.xml.mapper=TRACE diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml index 482f7086..cceaf408 100644 --- a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml @@ -25,6 +25,5 @@ - diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/HotelMapper.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/custommapper/HotelMapper.xml similarity index 100% rename from mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/mapper/HotelMapper.xml rename to mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/custommapper/HotelMapper.xml From dbf2cd04c46adfe17f39a703c2da1e67fafdfec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Thu, 17 Oct 2024 10:59:42 +0800 Subject: [PATCH 13/13] :construction_worker: use actions/setup-java graalvm https://github.com/actions/setup-java/issues/667 https://github.com/actions/setup-java/pull/501 --- .github/workflows/native.yaml | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 183cb869..6a72642b 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -24,7 +24,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest, macOS-latest ] - java: [ 17.0.9, 21.0.2, 22.0.2 ] + java: [ '17.0.12', '21', '22' ] fail-fast: false max-parallel: 5 name: Test GraalVM JDK ${{ matrix.java }}, ${{ matrix.os }} @@ -32,31 +32,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Ubuntu Set up JDK - if: ${{ matrix.os == 'ubuntu-latest' }} - run: | - JAVA_HOME=$RUNNER_WORKSPACE/.graalvm - echo $JAVA_HOME - mkdir -p $JAVA_HOME - echo "JAVA_HOME=$JAVA_HOME" >> $GITHUB_ENV - curl -L -o graalvm.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${{ matrix.java }}/graalvm-community-jdk-${{ matrix.java }}_linux-x64_bin.tar.gz - tar -zxvf graalvm.tar.gz -C $JAVA_HOME --strip-components=1 - ls -lh $JAVA_HOME - mvn -v - - - name: MacOS Set up JDK - if: ${{ matrix.os == 'macOS-latest' }} - run: | - JAVA_HOME=$RUNNER_WORKSPACE/.graalvm - echo $JAVA_HOME - mkdir -p $JAVA_HOME - curl -L -o graalvm.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${{ matrix.java }}/graalvm-community-jdk-${{ matrix.java }}_macos-x64_bin.tar.gz - tar -zxvf graalvm.tar.gz -C $JAVA_HOME --strip-components=1 - JAVA_HOME=$RUNNER_WORKSPACE/.graalvm/Contents/Home - echo $JAVA_HOME - echo "JAVA_HOME=$JAVA_HOME" >> $GITHUB_ENV - ls -lh $JAVA_HOME - mvn -v + - uses: actions/setup-java@v4 + with: + distribution: 'graalvm' + java-version: ${{ matrix.java }} - name: Cache modules uses: actions/cache@v4