Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ jobs:
matrix:
cache: [maven]
distribution: [temurin]
java: [21, 25, 26-ea]
os: [macos-latest, ubuntu-latest, windows-latest]
java: [17, 21]
os: [ubuntu-latest, windows-latest]
fail-fast: false
max-parallel: 6
name: Test JDK ${{ matrix.java }}, ${{ matrix.os }}
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/samples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ jobs:
- name: Set up GraalVM
uses: graalvm/setup-graalvm@03e8abf916fd0e281b2efe7b2da3378bb0a1d085 # v1
with:
version: 'dev'
java-version: ${{ matrix.java }}
components: 'native-image'
distribution: 'graalvm-community'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Cache local Maven repository
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
Expand All @@ -54,11 +53,11 @@ jobs:
java --version
native-image --version
- name: Build native image
run: ./mvnw -pl core,extensions,samples/${{ matrix.sample }} -U -D"maven.test.skip" -Pnative -D"license.skip=true" clean package -B -V --no-transfer-progress
run: ./mvnw -pl core,extensions,samples,samples/${{ matrix.sample }} -U -D"maven.test.skip" -Pnative -D"license.skip=true" clean package -B -V --no-transfer-progress
- name: Run with native image
run: ./samples/${{ matrix.sample }}/target/mybatis-spring-native-sample-${{ matrix.sample }}
- name: Run with executable jar on AOT mode
run: java -DspringAot=true -jar ./samples/${{ matrix.sample }}/target/mybatis-spring-native-sample-${{ matrix.sample }}-exec.jar
run: java -Dspring.aot.enabled=true -jar ./samples/${{ matrix.sample }}/target/mybatis-spring-native-sample-${{ matrix.sample }}-exec.jar
- name: Run with executable jar
run: java -jar ./samples/${{ matrix.sample }}/target/mybatis-spring-native-sample-${{ matrix.sample }}-exec.jar
- name: Verify running with native image for ubuntu
Expand Down
10 changes: 0 additions & 10 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,6 @@
<version>${mybatis-spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
*/
package org.mybatis.spring.nativex;

import static org.springframework.nativex.hint.TypeAccess.DECLARED_CLASSES;
import static org.springframework.nativex.hint.TypeAccess.DECLARED_CONSTRUCTORS;
import static org.springframework.nativex.hint.TypeAccess.DECLARED_FIELDS;
import static org.springframework.nativex.hint.TypeAccess.DECLARED_METHODS;
import static org.springframework.nativex.hint.TypeAccess.PUBLIC_CLASSES;
import static org.springframework.nativex.hint.TypeAccess.PUBLIC_CONSTRUCTORS;
import static org.springframework.nativex.hint.TypeAccess.PUBLIC_FIELDS;
import static org.springframework.nativex.hint.TypeAccess.PUBLIC_METHODS;

import org.apache.ibatis.cache.decorators.FifoCache;
import org.apache.ibatis.cache.decorators.LruCache;
import org.apache.ibatis.cache.decorators.SoftCache;
Expand All @@ -41,12 +32,11 @@
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.nativex.hint.InitializationHint;
import org.springframework.nativex.hint.InitializationTime;
import org.springframework.nativex.hint.NativeHint;
import org.springframework.nativex.hint.ResourceHint;
import org.springframework.nativex.hint.TypeHint;
import org.springframework.nativex.type.NativeConfiguration;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.util.ClassUtils;

/**
* Registers hints to make a MyBatis Core components work in a Spring Native context.
Expand All @@ -56,53 +46,27 @@
*
* @see MyBatisMapperNativeConfigurationProcessor
*/
// @formatter:off
@NativeHint(
trigger = SqlSessionFactory.class,
initialization = @InitializationHint(
initTime = InitializationTime.BUILD,
types = org.apache.ibatis.type.JdbcType.class
),
options = "--initialize-at-build-time=org.apache.ibatis.type.JdbcType",
resources = @ResourceHint(
patterns = {
"org/apache/ibatis/builder/xml/.*.dtd",
"org/apache/ibatis/builder/xml/.*.xsd"
}
)
)
@TypeHint(
types = {
RawLanguageDriver.class,
XMLLanguageDriver.class,
RuntimeSupport.class,
ProxyFactory.class,
Slf4jImpl.class,
Log.class,
JakartaCommonsLoggingImpl.class,
Log4j2Impl.class,
Jdk14LoggingImpl.class,
StdOutImpl.class,
NoLoggingImpl.class,
SqlSessionFactory.class,
PerpetualCache.class,
FifoCache.class,
LruCache.class,
SoftCache.class,
WeakCache.class
},
typeNames = "org.apache.ibatis.logging.log4j.Log4jImpl",
access = {
PUBLIC_CONSTRUCTORS,
PUBLIC_CLASSES,
PUBLIC_FIELDS,
PUBLIC_METHODS,
DECLARED_CLASSES,
DECLARED_CONSTRUCTORS,
DECLARED_FIELDS,
DECLARED_METHODS
public class MyBatisCoreNativeConfiguration implements RuntimeHintsRegistrar {

private static final MemberCategory[] MEMBER_CATEGORIES = { MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS,
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.PUBLIC_FIELDS, MemberCategory.DECLARED_FIELDS,
MemberCategory.PUBLIC_CLASSES, MemberCategory.DECLARED_CLASSES };

@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (!ClassUtils.isPresent("org.apache.ibatis.session.SqlSessionFactory", classLoader)) {
return;
}
)
// @formatter:on
public class MyBatisCoreNativeConfiguration implements NativeConfiguration {
for (Class<?> type : new Class<?>[] { RawLanguageDriver.class, XMLLanguageDriver.class, RuntimeSupport.class,
ProxyFactory.class, Slf4jImpl.class, Log.class, JakartaCommonsLoggingImpl.class, Log4j2Impl.class,
Jdk14LoggingImpl.class, StdOutImpl.class, NoLoggingImpl.class, SqlSessionFactory.class, PerpetualCache.class,
FifoCache.class, LruCache.class, SoftCache.class, WeakCache.class }) {
hints.reflection().registerType(type, MEMBER_CATEGORIES);
}
hints.reflection().registerType(TypeReference.of("org.apache.ibatis.logging.log4j.Log4jImpl"), MEMBER_CATEGORIES);
hints.resources().registerPattern("org/apache/ibatis/builder/xml/*.dtd");
hints.resources().registerPattern("org/apache/ibatis/builder/xml/*.xsd");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,61 +18,52 @@
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.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.BeanDefinitionPostProcessor;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils;

/**
* The {@code BeanDefinitionPostProcessor} for customizing a {@code MapperFactoryBean}.
* The {@code BeanRegistrationAotProcessor} for customizing a {@code MapperFactoryBean}.
* <p>
* This class is public so that Spring's AOT service loading from {@code META-INF/spring/aot.factories} can instantiate
* it.
*
* @author Stéphane Nicoll
* @author Kazuki Shimizu
*/
class MyBatisMapperFactoryBeanPostProcessor implements BeanDefinitionPostProcessor, BeanFactoryAware {
public class MyBatisMapperFactoryBeanPostProcessor implements BeanRegistrationAotProcessor {

private static final Log LOG = LogFactory.getLog(MyBatisMapperFactoryBeanPostProcessor.class);

private static final String MAPPER_FACTORY_BEAN = "org.mybatis.spring.mapper.MapperFactoryBean";

private ConfigurableBeanFactory beanFactory;

@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}

@Override
public void postProcessBeanDefinition(String beanName, RootBeanDefinition beanDefinition) {
if (ClassUtils.isPresent(MAPPER_FACTORY_BEAN, this.beanFactory.getBeanClassLoader())) {
resolveMapperFactoryBeanTypeIfNecessary(beanDefinition);
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
if (!ClassUtils.isPresent(MAPPER_FACTORY_BEAN, beanClass.getClassLoader())) {
return null;
}
}

private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
if (!beanDefinition.hasBeanClass() || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
return;
if (!MapperFactoryBean.class.isAssignableFrom(beanClass)) {
return null;
}
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
Class<?> mapperInterface = getMapperInterface(beanDefinition);
if (mapperInterface != null) {
// Exposes a generic type information to context for prevent early initializing
beanDefinition
.setTargetType(ResolvableType.forClassWithGenerics(beanDefinition.getBeanClass(), mapperInterface));
try {
Class<?> mapperInterface = (Class<?>) beanDefinition.getPropertyValues().get("mapperInterface");
if (mapperInterface != null) {
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(beanClass, mapperInterface));
}
} catch (Exception e) {
LOG.debug("Fail getting mapper interface type.", e);
}
}
}

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;
}
ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
constructorArgumentValues.clear();
return null;
}

}
Loading
Loading