diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml new file mode 100644 index 000000000..6a72642bd --- /dev/null +++ b/.github/workflows/native.yaml @@ -0,0 +1,61 @@ +# +# 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.12', '21', '22' ] + fail-fast: false + max-parallel: 5 + name: Test GraalVM JDK ${{ matrix.java }}, ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + distribution: 'graalvm' + java-version: ${{ matrix.java }} + + - 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 + + #- name: MacOS Prerequisites + # if: ${{ matrix.os == 'macOS-latest' }} + # run: xcode-select --install + + - name: Test with Spring Boot Native Latest + 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: | + mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/target/mybatis-spring-boot-sample-graalvm-annotation + mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/target/mybatis-spring-boot-sample-graalvm-xml 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 000000000..74d241c62 --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MyBatisBeanFactoryInitializationAotProcessor.java @@ -0,0 +1,181 @@ +/* + * 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.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.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 + */ +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 String MAPPER_LOCATIONS = MybatisProperties.MYBATIS_PREFIX + ".mapper-locations"; + + 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(); + + Environment environment = beanFactory.getBean(Environment.class); + configLocation(environment, hints); + mapperLocations(environment, hints); + + 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 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(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) { + 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 000000000..5b4e6f12d --- /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 {@link MergedBeanDefinitionPostProcessor} for customizing a {@link 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 000000000..d8f086cff --- /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,19 @@ +[ + { "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": [] }] }, + { "name": "java.util.HashMap", "methods": [{ "name": "", "parameterTypes": [] }] }, + { "name": "java.util.TreeSet", "methods": [{ "name": "", "parameterTypes": [] }] }, + { "name": "java.util.HashSet", "methods": [{ "name": "", "parameterTypes": [] }] }, + { "name": "org.apache.ibatis.session.Configuration", "methods": [{ "name": "", "parameterTypes": [] }] }, + { "name": "org.mybatis.spring.boot.autoconfigure.SpringBootVFS", "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/mybatis-resource.json b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/mybatis-resource.json new file mode 100644 index 000000000..d25f7bab3 --- /dev/null +++ b/mybatis-spring-boot-autoconfigure/src/main/resources/META-INF/native-image/org.mybatis.spring.boot/mybatis-spring-boot-autoconfigure/mybatis-resource.json @@ -0,0 +1,10 @@ +{ + "resources": { + "includes": [ + { "pattern": "org/apache/ibatis/builder/xml/mybatis-3-config.dtd" }, + { "pattern": "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd" }, + { "pattern": "org/apache/ibatis/builder/xml/mybatis-config.xsd" }, + { "pattern": "org/apache/ibatis/builder/xml/mybatis-mapper.xsd" } + ] + } +} 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 000000000..f7db4aa3f --- /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 -H:ResourceConfigurationResources=${.}/mybatis-resource.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 000000000..c319033dd --- /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 2fad2b7c9..91a4e32f2 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 000000000..a81590a5b --- /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 000000000..bad5a4711 --- /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 000000000..b00677d9b --- /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 000000000..117a378e5 --- /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,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; + +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")); + 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")); + } + +} 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 000000000..67764b598 --- /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 000000000..5c1e515a3 --- /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,53 @@ +/* + * 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 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 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); + + @Select("select id, name, state, country from city where state = #{state}") + List listByState(@Param("state") String state); + + @Select("select id, name, state, country from city where state = #{state}") + Map mapByState(@Param("state") String state); + + @Select("select id, name, state, country from city where state = #{state}") + List> listMapByState(@Param("state") String state); + + @Select("select state from city where country = #{country}") + TreeSet treeSetStateByState(@Param("country") String country); + + @Select("select state from city where country = #{country}") + HashSet hashSetStateByState(@Param("country") String country); + +} 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 000000000..2845bb39c --- /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 000000000..0c605f5f5 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-annotation/src/main/resources/data.sql @@ -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. +-- + +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'); 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 000000000..b3e263bb8 --- /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 000000000..44c15a26b --- /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 000000000..f48ade151 --- /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,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.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"); + 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-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 000000000..6daa8d07c --- /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,44 @@ +/* + * 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"); + 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-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 000000000..01daf22d3 --- /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,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.annotation.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.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"); + } + + @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-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 000000000..13f8768c6 --- /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/mybatis-spring-boot-sample-graalvm-xml/LICENSE_HEADER b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/LICENSE_HEADER new file mode 100644 index 000000000..a81590a5b --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/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-xml/format.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/format.xml new file mode 100644 index 000000000..bad5a4711 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/format.xml @@ -0,0 +1,22 @@ + + + + + + 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 000000000..02dcb64de --- /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 000000000..daf59b614 --- /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 000000000..eab35b24f --- /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 000000000..cfaf35c4a --- /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 000000000..873c72396 --- /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 000000000..6ac8f2b55 --- /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 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); + + 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 000000000..2b2fa3a99 --- /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 000000000..0f33d9bbc --- /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,7 @@ +{ + "resources": { + "includes": [ + { "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 new file mode 100644 index 000000000..e660f5f33 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/application.properties @@ -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. +# + +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/data.sql b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/data.sql new file mode 100644 index 000000000..16e36ecf5 --- /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 000000000..cceaf408b --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/mybatis-config.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/custommapper/HotelMapper.xml b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/custommapper/HotelMapper.xml new file mode 100644 index 000000000..6ea0cb134 --- /dev/null +++ b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/sample/mybatis/graalvm/xml/custommapper/HotelMapper.xml @@ -0,0 +1,26 @@ + + + + + + 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 000000000..25ab2295d --- /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/schema.sql b/mybatis-spring-boot-samples/mybatis-spring-boot-sample-graalvm-xml/src/main/resources/schema.sql new file mode 100644 index 000000000..34e24c728 --- /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 000000000..6e91d18cc --- /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 000000000..b46c76095 --- /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 000000000..5be3c2465 --- /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 000000000..ee988fe6e --- /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 000000000..35c0466fd --- /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 000000000..75563e944 --- /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 000000000..633577085 --- /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 000000000..82416a081 --- /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 14a9ab91f..52888f037 100644 --- a/mybatis-spring-boot-samples/pom.xml +++ b/mybatis-spring-boot-samples/pom.xml @@ -1,7 +1,7 @@