org.springframework.boot
spring-boot-starter-test
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisCoreNativeConfiguration.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisCoreNativeConfiguration.java
index 7af0522..d4002d5 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisCoreNativeConfiguration.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisCoreNativeConfiguration.java
@@ -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;
@@ -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.
@@ -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");
+ }
+
}
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessor.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessor.java
index 44aa809..9238099 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessor.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessor.java
@@ -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}.
+ *
+ * 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;
}
}
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessor.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessor.java
index f799f8a..39d3790 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessor.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessor.java
@@ -15,19 +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 static org.springframework.nativex.hint.TypeAccess.QUERY_DECLARED_CONSTRUCTORS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_DECLARED_METHODS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_CONSTRUCTORS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_METHODS;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.function.Function;
@@ -37,14 +24,14 @@
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import org.mybatis.spring.mapper.MapperFactoryBean;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.BeanFactoryNativeConfigurationProcessor;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeProxyEntry;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeResourcesEntry;
+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.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.nativex.hint.TypeAccess;
+import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -54,69 +41,84 @@
* @author Kazuki Shimizu
* @author Josh Long
*/
-public class MyBatisMapperNativeConfigurationProcessor implements BeanFactoryNativeConfigurationProcessor {
+public class MyBatisMapperNativeConfigurationProcessor implements BeanFactoryInitializationAotProcessor {
private static final String MAPPER_FACTORY_BEAN = "org.mybatis.spring.mapper.MapperFactoryBean";
- private static final TypeAccess[] TYPE_ACCESSES = { PUBLIC_CONSTRUCTORS, PUBLIC_CLASSES, PUBLIC_FIELDS,
- PUBLIC_METHODS, DECLARED_CLASSES, DECLARED_CONSTRUCTORS, DECLARED_FIELDS, DECLARED_METHODS,
- QUERY_DECLARED_METHODS, QUERY_PUBLIC_METHODS, QUERY_DECLARED_CONSTRUCTORS, QUERY_PUBLIC_CONSTRUCTORS };
+ 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 };
/**
* {@inheritDoc}
*/
@Override
- public void process(ConfigurableListableBeanFactory beanFactory, NativeConfigurationRegistry registry) {
+ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
if (!ClassUtils.isPresent(MAPPER_FACTORY_BEAN, beanFactory.getBeanClassLoader())) {
- return;
+ return null;
}
String[] beanNames = beanFactory.getBeanNamesForType(MapperFactoryBean.class);
+ if (beanNames.length == 0) {
+ return null;
+ }
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, registry);
- registry.proxy().add(NativeProxyEntry.ofInterfaces(mapperInterfaceType));
- registry.resources()
- .add(NativeResourcesEntry.of(mapperInterfaceType.getName().replace('.', '/').concat(".xml")));
- registerMapperRelationships(mapperInterfaceType, registry);
- }
+ BeanDefinition beanDefinition = beanFactory
+ .getBeanDefinition(beanName.startsWith("&") ? beanName.substring(1) : beanName);
+ ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
+ if (!constructorArgumentValues.isEmpty()) {
+ constructorArgumentValues.clear();
}
}
+ return (generationContext, beanFactoryInitializationCode) -> {
+ RuntimeHints hints = generationContext.getRuntimeHints();
+ for (String beanName : beanNames) {
+ BeanDefinition beanDefinition = beanFactory
+ .getBeanDefinition(beanName.startsWith("&") ? beanName.substring(1) : beanName);
+ 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);
+ hints.resources().registerPattern(mapperInterfaceType.getName().replace('.', '/').concat(".xml"));
+ registerMapperRelationships(mapperInterfaceType, hints);
+ }
+ }
+ }
+ };
}
- private void registerMapperRelationships(Class> mapperInterfaceType, NativeConfigurationRegistry registry) {
+ private void registerMapperRelationships(Class> mapperInterfaceType, RuntimeHints hints) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(mapperInterfaceType);
for (Method method : methods) {
if (method.getDeclaringClass() != Object.class) {
ReflectionUtils.makeAccessible(method);
- registerSqlProviderTypes(method, registry, SelectProvider.class, SelectProvider::value, SelectProvider::type);
- registerSqlProviderTypes(method, registry, InsertProvider.class, InsertProvider::value, InsertProvider::type);
- registerSqlProviderTypes(method, registry, UpdateProvider.class, UpdateProvider::value, UpdateProvider::type);
- registerSqlProviderTypes(method, registry, DeleteProvider.class, DeleteProvider::value, DeleteProvider::type);
+ registerSqlProviderTypes(method, hints, SelectProvider.class, SelectProvider::value, SelectProvider::type);
+ registerSqlProviderTypes(method, hints, InsertProvider.class, InsertProvider::value, InsertProvider::type);
+ registerSqlProviderTypes(method, hints, UpdateProvider.class, UpdateProvider::value, UpdateProvider::type);
+ registerSqlProviderTypes(method, hints, DeleteProvider.class, DeleteProvider::value, DeleteProvider::type);
Class> returnType = MyBatisMapperTypeUtils.resolveReturnClass(mapperInterfaceType, method);
- registerReflectionTypeIfNecessary(returnType, registry);
+ registerReflectionTypeIfNecessary(returnType, hints);
MyBatisMapperTypeUtils.resolveParameterClasses(mapperInterfaceType, method)
- .forEach(x -> registerReflectionTypeIfNecessary(x, registry));
+ .forEach(x -> registerReflectionTypeIfNecessary(x, hints));
}
}
}
@SafeVarargs
- private final void registerSqlProviderTypes(Method method,
- NativeConfigurationRegistry registry, Class annotationType, Function>... providerTypeResolvers) {
+ private final void registerSqlProviderTypes(Method method, RuntimeHints hints,
+ Class annotationType, Function>... providerTypeResolvers) {
for (T annotation : method.getAnnotationsByType(annotationType)) {
for (Function> providerTypeResolver : providerTypeResolvers) {
- registerReflectionTypeIfNecessary(providerTypeResolver.apply(annotation), registry);
+ registerReflectionTypeIfNecessary(providerTypeResolver.apply(annotation), hints);
}
}
}
- private void registerReflectionTypeIfNecessary(Class> type, NativeConfigurationRegistry registry) {
+ private void registerReflectionTypeIfNecessary(Class> type, RuntimeHints hints) {
if (!type.isPrimitive() && !type.getName().startsWith("java")) {
- registry.reflection().forType(type).withAccess(TYPE_ACCESSES);
+ hints.reflection().registerType(type, MEMBER_CATEGORIES);
}
}
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisResourcesScan.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisResourcesScan.java
index 7806f35..5615331 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisResourcesScan.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisResourcesScan.java
@@ -19,8 +19,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import org.springframework.aot.hint.MemberCategory;
import org.springframework.context.annotation.Import;
-import org.springframework.nativex.hint.TypeAccess;
/**
* The annotation that indicates scan rules of resources for running on native-image.
@@ -102,7 +102,7 @@
*
* @return access scopes for applying scanned classes to reflection hint
*/
- TypeAccess[] typeAccesses() default {};
+ MemberCategory[] typeAccesses() default {};
/**
* Return location patterns for adding resource hint file under classpath.
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesHolder.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesHolder.java
index c1ad9ab..a0726e2 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesHolder.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesHolder.java
@@ -30,6 +30,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.type.TypeHandler;
+import org.springframework.aot.hint.MemberCategory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
@@ -44,7 +45,6 @@
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
-import org.springframework.nativex.hint.TypeAccess;
import org.springframework.util.ClassUtils;
/**
@@ -58,7 +58,7 @@ public class MyBatisScannedResourcesHolder {
private Set> typeHandlerClasses;
private Set mapperLocations;
private Set> reflectionClasses;
- private TypeAccess[] reflectionTypeAccesses;
+ private MemberCategory[] reflectionTypeAccesses;
private Set resourceLocations;
/**
@@ -148,7 +148,7 @@ public Set> getReflectionClasses() {
* access scopes for applying reflection type that scanned
*/
@SuppressWarnings("unused")
- public void setReflectionTypeAccesses(TypeAccess[] reflectionTypeAccesses) {
+ public void setReflectionTypeAccesses(MemberCategory[] reflectionTypeAccesses) {
this.reflectionTypeAccesses = reflectionTypeAccesses;
}
@@ -157,7 +157,7 @@ public void setReflectionTypeAccesses(TypeAccess[] reflectionTypeAccesses) {
*
* @return access scopes for applying reflection type that scanned
*/
- public TypeAccess[] getReflectionTypeAccesses() {
+ public MemberCategory[] getReflectionTypeAccesses() {
return reflectionTypeAccesses;
}
@@ -183,7 +183,9 @@ public Set getResourceLocations() {
static class Registrar implements ImportBeanDefinitionRegistrar {
private static final Log LOG = LogFactory.getLog(Registrar.class);
- private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();
+ // Instance field (not static) to avoid URL caching in PathMatchingResourcePatternResolver
+ // when used across multiple application contexts (relevant since Spring Framework 6.x)
+ private final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();
private static final Pattern JAR_RESOURCE_PREFIX_PATTERN = Pattern.compile(".*\\.jar!/");
private static final boolean PRESENT_TYPE_HANDLER = ClassUtils.isPresent("org.apache.ibatis.type.TypeHandler",
@@ -238,7 +240,7 @@ protected void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefin
private Set> scanClasses(String[] packagePatterns, Class> assignableType) throws IOException {
Set> classes = new HashSet<>();
for (String packagePattern : packagePatterns) {
- Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ Resource[] resources = resourcePatternResolver.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class");
for (Resource resource : resources) {
try {
@@ -267,7 +269,7 @@ private Set scanResources(String[] mapperLocationPatterns) {
private Resource[] getResources(String locationPattern) {
try {
- return RESOURCE_PATTERN_RESOLVER.getResources(locationPattern);
+ return resourcePatternResolver.getResources(locationPattern);
} catch (IOException e) {
LOG.debug("Fail getting resources. locationPattern: " + locationPattern, e);
return new Resource[0];
@@ -297,7 +299,7 @@ private String determineRelativePath(Resource resource) throws IOException {
for (int i = path.getNameCount() - 1; i >= 0; i--) {
sb.insert(0, path.getName(i));
String relativePath = sb.toString();
- if (RESOURCE_PATTERN_RESOLVER.getResource(relativePath).exists()) {
+ if (resourcePatternResolver.getResource(relativePath).exists()) {
return relativePath;
}
sb.insert(0, '/');
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessor.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessor.java
index 23c7bd2..2c7367c 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessor.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessor.java
@@ -15,65 +15,60 @@
*/
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 static org.springframework.nativex.hint.TypeAccess.QUERY_DECLARED_CONSTRUCTORS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_DECLARED_METHODS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_CONSTRUCTORS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_METHODS;
-
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.BeanFactoryNativeConfigurationProcessor;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeResourcesEntry;
+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.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.nativex.hint.TypeAccess;
/**
* Finds and registers reflection and resource hints for all MyBatisScannedResourcesHolder in the {@code BeanFactory}.
*
* @author Kazuki Shimizu
*/
-public class MyBatisScannedResourcesNativeConfigurationProcessor implements BeanFactoryNativeConfigurationProcessor {
+public class MyBatisScannedResourcesNativeConfigurationProcessor implements BeanFactoryInitializationAotProcessor {
- private static final TypeAccess[] DEFAULT_TYPE_ACCESSES = { PUBLIC_CONSTRUCTORS, PUBLIC_CLASSES, PUBLIC_FIELDS,
- PUBLIC_METHODS, DECLARED_CLASSES, DECLARED_CONSTRUCTORS, DECLARED_FIELDS, DECLARED_METHODS,
- QUERY_DECLARED_METHODS, QUERY_PUBLIC_METHODS, QUERY_DECLARED_CONSTRUCTORS, QUERY_PUBLIC_CONSTRUCTORS };
+ private static final MemberCategory[] DEFAULT_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 };
/**
* {@inheritDoc}
*/
@Override
- public void process(ConfigurableListableBeanFactory beanFactory, NativeConfigurationRegistry registry) {
+ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
String[] beanNames = beanFactory.getBeanNamesForType(MyBatisScannedResourcesHolder.class);
- for (String beanName : beanNames) {
- BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
- @SuppressWarnings("unchecked")
- Set resourceLocations = (Set) Optional
- .ofNullable(beanDefinition.getPropertyValues().getPropertyValue("resourceLocations"))
- .map(PropertyValue::getValue).orElse(Collections.emptySet());
- resourceLocations.forEach(x -> registry.resources().add(NativeResourcesEntry.of(x)));
- @SuppressWarnings("unchecked")
- Set> reflectionClasses = (Set>) Optional
- .ofNullable(beanDefinition.getPropertyValues().getPropertyValue("reflectionClasses"))
- .map(PropertyValue::getValue).orElse(Collections.emptySet());
- TypeAccess[] reflectionTypeAccesses = (TypeAccess[]) Optional
- .ofNullable(beanDefinition.getPropertyValues().getPropertyValue("reflectionTypeAccesses"))
- .map(PropertyValue::getValue).orElse(DEFAULT_TYPE_ACCESSES);
- reflectionClasses.forEach(x -> registry.reflection().forType(x)
- .withAccess(reflectionTypeAccesses.length == 0 ? DEFAULT_TYPE_ACCESSES : reflectionTypeAccesses).build());
+ if (beanNames.length == 0) {
+ return null;
}
+ return (generationContext, beanFactoryInitializationCode) -> {
+ RuntimeHints hints = generationContext.getRuntimeHints();
+ for (String beanName : beanNames) {
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ @SuppressWarnings("unchecked")
+ Set resourceLocations = (Set) Optional
+ .ofNullable(beanDefinition.getPropertyValues().getPropertyValue("resourceLocations"))
+ .map(PropertyValue::getValue).orElse(Collections.emptySet());
+ resourceLocations.forEach(hints.resources()::registerPattern);
+ @SuppressWarnings("unchecked")
+ Set> reflectionClasses = (Set>) Optional
+ .ofNullable(beanDefinition.getPropertyValues().getPropertyValue("reflectionClasses"))
+ .map(PropertyValue::getValue).orElse(Collections.emptySet());
+ MemberCategory[] memberCategories = (MemberCategory[]) Optional
+ .ofNullable(beanDefinition.getPropertyValues().getPropertyValue("reflectionTypeAccesses"))
+ .map(PropertyValue::getValue).orElse(DEFAULT_MEMBER_CATEGORIES);
+ MemberCategory[] effectiveCategories = (memberCategories.length == 0) ? DEFAULT_MEMBER_CATEGORIES
+ : memberCategories;
+ reflectionClasses.forEach(x -> hints.reflection().registerType(x, effectiveCategories));
+ }
+ };
}
}
diff --git a/core/src/main/java/org/mybatis/spring/nativex/MyBatisSpringNativeConfiguration.java b/core/src/main/java/org/mybatis/spring/nativex/MyBatisSpringNativeConfiguration.java
index 297b6b0..1d24afc 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/MyBatisSpringNativeConfiguration.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/MyBatisSpringNativeConfiguration.java
@@ -15,47 +15,31 @@
*/
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.mybatis.spring.SqlSessionFactoryBean;
-import org.mybatis.spring.SqlSessionTemplate;
-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.util.ClassUtils;
/**
* Registers hints to make a MyBatis Spring component work in a Spring Native context.
*
* @author Kazuki Shimizu
*/
-// @formatter:off
-@NativeHint(
- trigger = SqlSessionTemplate.class,
- resources = @ResourceHint(
- patterns = "org/mybatis/spring/config/.*.xsd"
- )
-)
-@TypeHint(
- types = SqlSessionFactoryBean.class,
- access = {
- PUBLIC_CONSTRUCTORS,
- PUBLIC_CLASSES,
- PUBLIC_FIELDS,
- PUBLIC_METHODS,
- DECLARED_CLASSES,
- DECLARED_CONSTRUCTORS,
- DECLARED_FIELDS,
- DECLARED_METHODS
+public class MyBatisSpringNativeConfiguration 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.mybatis.spring.SqlSessionTemplate", classLoader)) {
+ return;
}
-)
-// @formatter:on
-public class MyBatisSpringNativeConfiguration implements NativeConfiguration {
+ hints.reflection().registerType(SqlSessionFactoryBean.class, MEMBER_CATEGORIES);
+ hints.resources().registerPattern("org/mybatis/spring/config/*.xsd");
+ }
+
}
diff --git a/core/src/main/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfiguration.java b/core/src/main/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfiguration.java
index afac990..bf0a2f0 100644
--- a/core/src/main/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfiguration.java
+++ b/core/src/main/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfiguration.java
@@ -20,7 +20,9 @@
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.mybatis.spring.boot.autoconfigure.SqlSessionFactoryBeanCustomizer;
+import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.nativex.MyBatisScannedResourcesHolder;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -62,4 +64,15 @@ SqlSessionFactoryBeanCustomizer mybatisScannedResourcesHolderSqlSessionFactoryBe
};
}
+ @Bean
+ static BeanFactoryPostProcessor mybatisMapperFactoryBeanDefinitionPostProcessor() {
+ return beanFactory -> {
+ String[] beanNames = beanFactory.getBeanNamesForType(MapperFactoryBean.class);
+ for (String beanName : beanNames) {
+ beanFactory.getBeanDefinition(beanName.startsWith("&") ? beanName.substring(1) : beanName)
+ .getConstructorArgumentValues().clear();
+ }
+ };
+ }
+
}
diff --git a/core/src/main/resources/META-INF/native-image/org.mybatis.spring.native/mybatis-spring-native-core/reflect-config.json b/core/src/main/resources/META-INF/native-image/org.mybatis.spring.native/mybatis-spring-native-core/reflect-config.json
new file mode 100644
index 0000000..b2ebe5f
--- /dev/null
+++ b/core/src/main/resources/META-INF/native-image/org.mybatis.spring.native/mybatis-spring-native-core/reflect-config.json
@@ -0,0 +1,37 @@
+[
+ {
+ "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.logging.stdout.StdOutImpl",
+ "allDeclaredConstructors": true,
+ "allDeclaredMethods": true
+ }
+]
diff --git a/core/src/main/resources/META-INF/spring.factories b/core/src/main/resources/META-INF/spring.factories
index 911d0e7..fb41395 100644
--- a/core/src/main/resources/META-INF/spring.factories
+++ b/core/src/main/resources/META-INF/spring.factories
@@ -14,13 +14,5 @@
# limitations under the License.
#
-org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.BeanFactoryNativeConfigurationProcessor=\
- org.mybatis.spring.nativex.MyBatisMapperNativeConfigurationProcessor,\
- org.mybatis.spring.nativex.MyBatisScannedResourcesNativeConfigurationProcessor
-org.springframework.context.annotation.BeanDefinitionPostProcessor=\
- org.mybatis.spring.nativex.MyBatisMapperFactoryBeanPostProcessor
-org.springframework.nativex.type.NativeConfiguration=\
- org.mybatis.spring.nativex.MyBatisCoreNativeConfiguration,\
- org.mybatis.spring.nativex.MyBatisSpringNativeConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.nativex.autoconfigure.MyBatisSpringNativeAutoConfiguration
diff --git a/core/src/main/resources/META-INF/spring/aot.factories b/core/src/main/resources/META-INF/spring/aot.factories
new file mode 100644
index 0000000..17f7a54
--- /dev/null
+++ b/core/src/main/resources/META-INF/spring/aot.factories
@@ -0,0 +1,6 @@
+org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
+org.mybatis.spring.nativex.MyBatisMapperFactoryBeanPostProcessor
+
+org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\
+org.mybatis.spring.nativex.MyBatisMapperNativeConfigurationProcessor,\
+org.mybatis.spring.nativex.MyBatisScannedResourcesNativeConfigurationProcessor
diff --git a/core/src/main/resources/META-INF/spring/org.springframework.aot.hint.RuntimeHintsRegistrar b/core/src/main/resources/META-INF/spring/org.springframework.aot.hint.RuntimeHintsRegistrar
new file mode 100644
index 0000000..28dbc85
--- /dev/null
+++ b/core/src/main/resources/META-INF/spring/org.springframework.aot.hint.RuntimeHintsRegistrar
@@ -0,0 +1,2 @@
+org.mybatis.spring.nativex.MyBatisCoreNativeConfiguration
+org.mybatis.spring.nativex.MyBatisSpringNativeConfiguration
diff --git a/core/src/main/resources/META-INF/spring/org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor b/core/src/main/resources/META-INF/spring/org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor
new file mode 100644
index 0000000..18ac79f
--- /dev/null
+++ b/core/src/main/resources/META-INF/spring/org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor
@@ -0,0 +1,2 @@
+org.mybatis.spring.nativex.MyBatisMapperNativeConfigurationProcessor
+org.mybatis.spring.nativex.MyBatisScannedResourcesNativeConfigurationProcessor
diff --git a/core/src/main/resources/META-INF/spring/org.springframework.beans.factory.aot.BeanRegistrationAotProcessor b/core/src/main/resources/META-INF/spring/org.springframework.beans.factory.aot.BeanRegistrationAotProcessor
new file mode 100644
index 0000000..5654ad5
--- /dev/null
+++ b/core/src/main/resources/META-INF/spring/org.springframework.beans.factory.aot.BeanRegistrationAotProcessor
@@ -0,0 +1 @@
+org.mybatis.spring.nativex.MyBatisMapperFactoryBeanPostProcessor
diff --git a/core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..81215fa
--- /dev/null
+++ b/core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.mybatis.spring.nativex.autoconfigure.MyBatisSpringNativeAutoConfiguration
diff --git a/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessorTest.java b/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessorTest.java
index 8ef4c55..0def189 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessorTest.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperFactoryBeanPostProcessorTest.java
@@ -15,12 +15,16 @@
*/
package org.mybatis.spring.nativex;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.nativex.mapper.SampleMapper;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
@@ -36,20 +40,41 @@ void resolveMapperInterfaceType() {
.rootBeanDefinition(MapperFactoryBean.class).addPropertyValue("mapperInterface", SampleMapper.class)
.getBeanDefinition();
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
- postProcess(beanDefinition);
+ postProcess(MapperFactoryBean.class, beanDefinition);
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isFalse();
Assertions.assertThat(beanDefinition.getTargetType()).isEqualTo(MapperFactoryBean.class);
Assertions.assertThat(beanDefinition.getResolvableType().getGenerics()).hasSize(1);
Assertions.assertThat(beanDefinition.getResolvableType().getGenerics()[0].toClass()).isEqualTo(SampleMapper.class);
}
+ @Test
+ void clearConstructorArgumentsWhenHasGenericConstructorArgument() {
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
+ .rootBeanDefinition(MapperFactoryBean.class).addConstructorArgValue(SampleMapper.class.getName())
+ .addPropertyValue("mapperInterface", SampleMapper.class).getBeanDefinition();
+ Assertions.assertThat(beanDefinition.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
+ postProcess(MapperFactoryBean.class, beanDefinition);
+ Assertions.assertThat(beanDefinition.getConstructorArgumentValues().isEmpty()).isTrue();
+ }
+
+ @Test
+ void clearConstructorArgumentsWhenHasIndexedConstructorArgument() {
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
+ .rootBeanDefinition(MapperFactoryBean.class).addConstructorArgValue(SampleMapper.class.getName())
+ .addPropertyValue("mapperInterface", SampleMapper.class).getBeanDefinition();
+ beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, "sampleMapperClass");
+ Assertions.assertThat(beanDefinition.getConstructorArgumentValues().getArgumentCount()).isEqualTo(2);
+ postProcess(MapperFactoryBean.class, beanDefinition);
+ Assertions.assertThat(beanDefinition.getConstructorArgumentValues().isEmpty()).isTrue();
+ }
+
@Test
void resolveMapperInterfaceTypeWhenMapperFactoryBeanSubclassWithOneGeneric() {
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(MapperFactoryBean2.class).addPropertyValue("mapperInterface", SampleMapper.class)
.getBeanDefinition();
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
- postProcess(beanDefinition);
+ postProcess(MapperFactoryBean2.class, beanDefinition);
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isFalse();
Assertions.assertThat(beanDefinition.getTargetType()).isEqualTo(MapperFactoryBean2.class);
Assertions.assertThat(beanDefinition.getResolvableType().getGenerics()).hasSize(1);
@@ -62,19 +87,21 @@ void resolveMapperInterfaceTypeWhenMapperFactoryBeanSubclassWithoutGeneric() {
.rootBeanDefinition(SampleMapperFactoryBean.class).addPropertyValue("mapperInterface", SampleMapper.class)
.getBeanDefinition();
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isFalse();
- postProcess(beanDefinition);
+ postProcess(SampleMapperFactoryBean.class, beanDefinition);
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isFalse();
}
- // TODO Now this case is limitation using MapperFactoryBean's subclass
+ // With BeanRegistrationAotProcessor, the processAheadOfTime method catches and ignores exceptions
+ // during type resolution (unlike the old BeanDefinitionPostProcessor which propagated them).
@Test
- void failResolveMapperInterfaceTypeWhenMapperFactoryBeanSubclassWithMultiGenerics() {
+ void skipResolveMapperInterfaceTypeWhenMapperFactoryBeanSubclassWithMultiGenerics() {
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(MapperFactoryBean3.class).addPropertyValue("mapperInterface", SampleMapper.class)
.getBeanDefinition();
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
- Assertions.assertThatIllegalArgumentException().isThrownBy(() -> postProcess(beanDefinition)).withMessage(
- "Mismatched number of generics specified for private static class org.mybatis.spring.nativex.MyBatisMapperFactoryBeanPostProcessorTest$MapperFactoryBean3");
+ postProcess(MapperFactoryBean3.class, beanDefinition);
+ // exception is caught and ignored, target type remains unset
+ Assertions.assertThat(beanDefinition.getTargetType()).isNull();
}
@Test
@@ -82,7 +109,7 @@ void skipResolveMapperInterfaceTypeWhenNotPresentMapperInterface() {
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(MapperFactoryBean.class).getBeanDefinition();
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
- postProcess(beanDefinition);
+ postProcess(MapperFactoryBean.class, beanDefinition);
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
Assertions.assertThat(beanDefinition.getTargetType()).isNull();
}
@@ -93,32 +120,24 @@ void skipResolveMapperInterfaceTypeWhenFailGetMapperInterface() {
.rootBeanDefinition(MapperFactoryBean.class).addPropertyValue("mapperInterface", "invalid value")
.getBeanDefinition();
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
- postProcess(beanDefinition);
+ postProcess(MapperFactoryBean.class, beanDefinition);
Assertions.assertThat(beanDefinition.getResolvableType().hasUnresolvableGenerics()).isTrue();
Assertions.assertThat(beanDefinition.getTargetType()).isNull();
}
- @Test
- void skipResolveMapperInterfaceTypeWhenNotPresentBeanClass() {
- RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition((Class>) null)
- .getBeanDefinition();
- postProcess(beanDefinition);
- Assertions.assertThat(beanDefinition.getTargetType()).isNull();
- }
-
@Test
void skipResolveMapperInterfaceTypeWhenBeanClassNotMapperBeanFactory() {
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition(String.class)
.getBeanDefinition();
- postProcess(beanDefinition);
+ postProcess(String.class, beanDefinition);
Assertions.assertThat(beanDefinition.getTargetType()).isNull();
}
- private void postProcess(RootBeanDefinition beanDefinition) {
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
- MyBatisMapperFactoryBeanPostProcessor processor = new MyBatisMapperFactoryBeanPostProcessor();
- processor.setBeanFactory(beanFactory);
- processor.postProcessBeanDefinition("testBean", beanDefinition);
+ private void postProcess(Class> beanClass, RootBeanDefinition beanDefinition) {
+ RegisteredBean registeredBean = mock(RegisteredBean.class);
+ doReturn(beanClass).when(registeredBean).getBeanClass();
+ when(registeredBean.getMergedBeanDefinition()).thenReturn(beanDefinition);
+ new MyBatisMapperFactoryBeanPostProcessor().processAheadOfTime(registeredBean);
}
private static class MapperFactoryBean2 extends MapperFactoryBean {
diff --git a/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessorTest.java b/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessorTest.java
index 414ea54..0f65385 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessorTest.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/MyBatisMapperNativeConfigurationProcessorTest.java
@@ -15,40 +15,24 @@
*/
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 static org.springframework.nativex.hint.TypeAccess.QUERY_DECLARED_CONSTRUCTORS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_DECLARED_METHODS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_CONSTRUCTORS;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_METHODS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.nativex.mapper.Sample2Mapper;
import org.mybatis.spring.nativex.mapper.Sample3Mapper;
import org.mybatis.spring.nativex.mapper.SampleMapper;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.DefaultNativeReflectionEntry;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeProxyEntry;
+import org.springframework.aot.generate.GenerationContext;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
+import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
+import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.nativex.domain.proxies.JdkProxyDescriptor;
-import org.springframework.nativex.domain.proxies.ProxiesDescriptor;
-import org.springframework.nativex.hint.TypeAccess;
/**
* Test cases for {@link MyBatisMapperNativeConfigurationProcessor}.
@@ -57,9 +41,10 @@
*/
class MyBatisMapperNativeConfigurationProcessorTest {
- private static final TypeAccess[] TYPE_ACCESSES = { PUBLIC_CONSTRUCTORS, PUBLIC_CLASSES, PUBLIC_FIELDS,
- PUBLIC_METHODS, DECLARED_CLASSES, DECLARED_CONSTRUCTORS, DECLARED_FIELDS, DECLARED_METHODS,
- QUERY_DECLARED_METHODS, QUERY_PUBLIC_METHODS, QUERY_DECLARED_CONSTRUCTORS, QUERY_PUBLIC_CONSTRUCTORS };
+ 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 };
@Test
@SuppressWarnings("java:S5961")
@@ -70,62 +55,62 @@ void registerMapperInterfaceAndRelationships() {
.addPropertyValue("mapperInterface", SampleMapper.class)
.addPropertyValue("sqlSessionTemplate", new RuntimeBeanNameReference("sqlSessionTemplate"))
.getBeanDefinition());
- NativeConfigurationRegistry registry = process(beanFactory);
+ RuntimeHints hints = process(beanFactory);
// reflection hint
{
- Map, DefaultNativeReflectionEntry> entries = registry.reflection().reflectionEntries()
- .collect(Collectors.toMap(DefaultNativeReflectionEntry::getType, x -> x));
- Assertions.assertThat(entries).hasSize(13);
- // mapper interface
- Assertions.assertThat(entries.get(SampleMapper.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- // mapper method argument and return type
- Assertions.assertThat(entries.get(SampleMapper.Sample.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.SampleParam.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.Sample2.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.Sample2Param.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- // sql provider
- Assertions.assertThat(entries.get(SampleMapper.SelectProviderClass1.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.SelectProviderClass2.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.InsertProviderClass1.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.InsertProviderClass2.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.UpdateProviderClass1.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.UpdateProviderClass2.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.DeleteProviderClass1.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(SampleMapper.DeleteProviderClass2.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
+ assertThat(hints.reflection().typeHints()).hasSize(13);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.class).withMemberCategories(MEMBER_CATEGORIES))
+ .accepts(hints);
+ assertThat(
+ RuntimeHintsPredicates.reflection().onType(SampleMapper.Sample.class).withMemberCategories(MEMBER_CATEGORIES))
+ .accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.SampleParam.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.Sample2.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.Sample2Param.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.SelectProviderClass1.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.SelectProviderClass2.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.InsertProviderClass1.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.InsertProviderClass2.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.UpdateProviderClass1.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.UpdateProviderClass2.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.DeleteProviderClass1.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(SampleMapper.DeleteProviderClass2.class)
+ .withMemberCategories(MEMBER_CATEGORIES)).accepts(hints);
}
// proxy hint
{
- List entries = new ArrayList<>(registry.proxy().getEntries());
- Assertions.assertThat(entries).hasSize(1);
- ProxiesDescriptor proxiesDescriptor = new ProxiesDescriptor();
- entries.forEach(x -> x.contribute(proxiesDescriptor));
- List jdkProxyDescriptors = new ArrayList<>(proxiesDescriptor.getProxyDescriptors());
- Assertions.assertThat(jdkProxyDescriptors).hasSize(1);
- Assertions.assertThat(jdkProxyDescriptors.get(0)).satisfies(x -> {
- Assertions.assertThat(x.isClassProxy()).isFalse();
- Assertions.assertThat(x.getTypes()).containsExactlyInAnyOrder("org.mybatis.spring.nativex.mapper.SampleMapper");
- });
+ assertThat(hints.proxies().jdkProxyHints()).hasSize(1);
+ assertThat(RuntimeHintsPredicates.proxies().forInterfaces(SampleMapper.class)).accepts(hints);
}
// resource hint
{
- Set resources = registry.resources().toResourcesDescriptor().getPatterns();
- Assertions.assertThat(resources).containsExactlyInAnyOrder("org/mybatis/spring/nativex/mapper/SampleMapper.xml");
+ assertThat(RuntimeHintsPredicates.resource().forResource("org/mybatis/spring/nativex/mapper/SampleMapper.xml"))
+ .accepts(hints);
}
}
+ @Test
+ void clearConstructorArgumentsForMapperFactoryBean() {
+ DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
+ beanFactory.registerBeanDefinition("sampleMapper", BeanDefinitionBuilder.rootBeanDefinition(MapperFactoryBean.class)
+ .addConstructorArgValue(SampleMapper.class.getName()).addPropertyValue("mapperInterface", SampleMapper.class)
+ .addPropertyValue("sqlSessionTemplate", new RuntimeBeanNameReference("sqlSessionTemplate"))
+ .getBeanDefinition());
+ RuntimeHints hints = process(beanFactory);
+ assertThat(hints.reflection().typeHints()).isNotEmpty();
+ assertThat(beanFactory.getBeanDefinition("sampleMapper").getConstructorArgumentValues().isEmpty()).isTrue();
+ }
+
@Test
void registerMultiMapperInterface() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@@ -139,42 +124,29 @@ void registerMultiMapperInterface() {
.addPropertyValue("mapperInterface", Sample3Mapper.class)
.addPropertyValue("sqlSessionTemplate", new RuntimeBeanNameReference("sqlSessionTemplate"))
.getBeanDefinition());
- NativeConfigurationRegistry registry = process(beanFactory);
+ RuntimeHints hints = process(beanFactory);
// reflection hint
{
- Map, DefaultNativeReflectionEntry> entries = registry.reflection().reflectionEntries()
- .collect(Collectors.toMap(DefaultNativeReflectionEntry::getType, x -> x));
- Assertions.assertThat(entries).hasSize(2);
- // mapper interface
- Assertions.assertThat(entries.get(Sample2Mapper.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
- Assertions.assertThat(entries.get(Sample3Mapper.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
+ assertThat(hints.reflection().typeHints()).hasSize(2);
+ assertThat(
+ RuntimeHintsPredicates.reflection().onType(Sample2Mapper.class).withMemberCategories(MEMBER_CATEGORIES))
+ .accepts(hints);
+ assertThat(
+ RuntimeHintsPredicates.reflection().onType(Sample3Mapper.class).withMemberCategories(MEMBER_CATEGORIES))
+ .accepts(hints);
}
// proxy hint
{
- List entries = new ArrayList<>(registry.proxy().getEntries());
- Assertions.assertThat(entries).hasSize(2);
- ProxiesDescriptor proxiesDescriptor = new ProxiesDescriptor();
- entries.forEach(x -> x.contribute(proxiesDescriptor));
- List jdkProxyDescriptors = new ArrayList<>(proxiesDescriptor.getProxyDescriptors());
- Assertions.assertThat(jdkProxyDescriptors).hasSize(2);
- Assertions.assertThat(jdkProxyDescriptors.get(0)).satisfies(x -> {
- Assertions.assertThat(x.isClassProxy()).isFalse();
- Assertions.assertThat(x.getTypes())
- .containsExactlyInAnyOrder("org.mybatis.spring.nativex.mapper.Sample2Mapper");
- });
- Assertions.assertThat(jdkProxyDescriptors.get(1)).satisfies(x -> {
- Assertions.assertThat(x.isClassProxy()).isFalse();
- Assertions.assertThat(x.getTypes())
- .containsExactlyInAnyOrder("org.mybatis.spring.nativex.mapper.Sample3Mapper");
- });
+ assertThat(hints.proxies().jdkProxyHints()).hasSize(2);
+ assertThat(RuntimeHintsPredicates.proxies().forInterfaces(Sample2Mapper.class)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.proxies().forInterfaces(Sample3Mapper.class)).accepts(hints);
}
// resource hint
{
- Set resources = registry.resources().toResourcesDescriptor().getPatterns();
- Assertions.assertThat(resources).containsExactlyInAnyOrder("org/mybatis/spring/nativex/mapper/Sample2Mapper.xml",
- "org/mybatis/spring/nativex/mapper/Sample3Mapper.xml");
+ assertThat(RuntimeHintsPredicates.resource().forResource("org/mybatis/spring/nativex/mapper/Sample2Mapper.xml"))
+ .accepts(hints);
+ assertThat(RuntimeHintsPredicates.resource().forResource("org/mybatis/spring/nativex/mapper/Sample3Mapper.xml"))
+ .accepts(hints);
}
}
@@ -186,34 +158,23 @@ void registerMapperInterfaceWithMapperFactoryBeanSubclass() {
.addPropertyValue("mapperInterface", Sample2Mapper.class)
.addPropertyValue("sqlSessionTemplate", new RuntimeBeanNameReference("sqlSessionTemplate"))
.getBeanDefinition());
- NativeConfigurationRegistry registry = process(beanFactory);
+ RuntimeHints hints = process(beanFactory);
// reflection hint
{
- Map, DefaultNativeReflectionEntry> entries = registry.reflection().reflectionEntries()
- .collect(Collectors.toMap(DefaultNativeReflectionEntry::getType, x -> x));
- Assertions.assertThat(entries).hasSize(1);
- // mapper interface
- Assertions.assertThat(entries.get(Sample2Mapper.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(TYPE_ACCESSES));
+ assertThat(hints.reflection().typeHints()).hasSize(1);
+ assertThat(
+ RuntimeHintsPredicates.reflection().onType(Sample2Mapper.class).withMemberCategories(MEMBER_CATEGORIES))
+ .accepts(hints);
}
// proxy hint
{
- List entries = new ArrayList<>(registry.proxy().getEntries());
- Assertions.assertThat(entries).hasSize(1);
- ProxiesDescriptor proxiesDescriptor = new ProxiesDescriptor();
- entries.forEach(x -> x.contribute(proxiesDescriptor));
- List jdkProxyDescriptors = new ArrayList<>(proxiesDescriptor.getProxyDescriptors());
- Assertions.assertThat(jdkProxyDescriptors).hasSize(1);
- Assertions.assertThat(jdkProxyDescriptors.get(0)).satisfies(x -> {
- Assertions.assertThat(x.isClassProxy()).isFalse();
- Assertions.assertThat(x.getTypes())
- .containsExactlyInAnyOrder("org.mybatis.spring.nativex.mapper.Sample2Mapper");
- });
+ assertThat(hints.proxies().jdkProxyHints()).hasSize(1);
+ assertThat(RuntimeHintsPredicates.proxies().forInterfaces(Sample2Mapper.class)).accepts(hints);
}
// resource hint
{
- Set resources = registry.resources().toResourcesDescriptor().getPatterns();
- Assertions.assertThat(resources).containsExactlyInAnyOrder("org/mybatis/spring/nativex/mapper/Sample2Mapper.xml");
+ assertThat(RuntimeHintsPredicates.resource().forResource("org/mybatis/spring/nativex/mapper/Sample2Mapper.xml"))
+ .accepts(hints);
}
}
@@ -224,19 +185,10 @@ void skipRegisterWhenMapperInterfaceNotPresent() {
BeanDefinitionBuilder.rootBeanDefinition(MapperFactoryBean.class)
.addPropertyValue("sqlSessionTemplate", new RuntimeBeanNameReference("sqlSessionTemplate"))
.getBeanDefinition());
- NativeConfigurationRegistry registry = process(beanFactory);
- // reflection hint
- {
- Assertions.assertThat(registry.reflection().reflectionEntries()).isEmpty();
- }
- // proxy hint
- {
- Assertions.assertThat(registry.proxy().getEntries()).isEmpty();
- }
- // resource hint
- {
- Assertions.assertThat(registry.resources().toResourcesDescriptor().getPatterns()).isEmpty();
- }
+ RuntimeHints hints = process(beanFactory);
+ assertThat(hints.reflection().typeHints()).isEmpty();
+ assertThat(hints.proxies().jdkProxyHints()).isEmpty();
+ assertThat(hints.resources().resourcePatternHints()).isEmpty();
}
@Test
@@ -246,25 +198,22 @@ void skipRegisterWhenMapperInterfaceIsNull() {
BeanDefinitionBuilder.rootBeanDefinition(MapperFactoryBean.class).addPropertyValue("mapperInterface", null)
.addPropertyValue("sqlSessionTemplate", new RuntimeBeanNameReference("sqlSessionTemplate"))
.getBeanDefinition());
- NativeConfigurationRegistry registry = process(beanFactory);
- // reflection hint
- {
- Assertions.assertThat(registry.reflection().reflectionEntries()).isEmpty();
- }
- // proxy hint
- {
- Assertions.assertThat(registry.proxy().getEntries()).isEmpty();
- }
- // resource hint
- {
- Assertions.assertThat(registry.resources().toResourcesDescriptor().getPatterns()).isEmpty();
- }
+ RuntimeHints hints = process(beanFactory);
+ assertThat(hints.reflection().typeHints()).isEmpty();
+ assertThat(hints.proxies().jdkProxyHints()).isEmpty();
+ assertThat(hints.resources().resourcePatternHints()).isEmpty();
}
- private NativeConfigurationRegistry process(DefaultListableBeanFactory beanFactory) {
- NativeConfigurationRegistry registry = new NativeConfigurationRegistry();
- new MyBatisMapperNativeConfigurationProcessor().process(beanFactory, registry);
- return registry;
+ private RuntimeHints process(DefaultListableBeanFactory beanFactory) {
+ RuntimeHints hints = new RuntimeHints();
+ GenerationContext generationContext = mock(GenerationContext.class);
+ when(generationContext.getRuntimeHints()).thenReturn(hints);
+ BeanFactoryInitializationAotContribution contribution = new MyBatisMapperNativeConfigurationProcessor()
+ .processAheadOfTime(beanFactory);
+ if (contribution != null) {
+ contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));
+ }
+ return hints;
}
private static class MyMapperFactoryBean extends MapperFactoryBean {
diff --git a/core/src/test/java/org/mybatis/spring/nativex/MyBatisResourcesScanTest.java b/core/src/test/java/org/mybatis/spring/nativex/MyBatisResourcesScanTest.java
index 4f88932..bc48d0e 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/MyBatisResourcesScanTest.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/MyBatisResourcesScanTest.java
@@ -35,9 +35,9 @@
import org.mybatis.spring.nativex.entity.City;
import org.mybatis.spring.nativex.entity.Country;
import org.mybatis.spring.nativex.marker.StandardEntity;
+import org.springframework.aot.hint.MemberCategory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
-import org.springframework.nativex.hint.TypeAccess;
import org.springframework.util.ClassUtils;
class MyBatisResourcesScanTest {
@@ -149,7 +149,8 @@ void scanReflectionType() {
Assertions.assertThat(holder.getTypeHandlerClasses()).isEmpty();
Assertions.assertThat(holder.getReflectionClasses()).containsExactlyInAnyOrder(City.class, Country.class);
Assertions.assertThat(holder.getResourceLocations()).isEmpty();
- Assertions.assertThat(holder.getReflectionTypeAccesses()).containsExactlyInAnyOrder(TypeAccess.DECLARED_CLASSES);
+ Assertions.assertThat(holder.getReflectionTypeAccesses())
+ .containsExactlyInAnyOrder(MemberCategory.DECLARED_CLASSES);
}
@Test
@@ -282,12 +283,12 @@ static class ConfigurationForScanMapperLocations {
static class ConfigurationForScanMapperLocationsWithMultiPattern {
}
- @MyBatisResourcesScan(reflectionTypePackages = "org.mybatis.spring.nativex.entity", typeAccesses = TypeAccess.DECLARED_CLASSES)
+ @MyBatisResourcesScan(reflectionTypePackages = "org.mybatis.spring.nativex.entity", typeAccesses = MemberCategory.DECLARED_CLASSES)
@Configuration
static class ConfigurationForScanReflectionType {
}
- @MyBatisResourcesScan(reflectionTypePackages = "org.mybatis.spring.nativex.entity", reflectionTypeSupperType = StandardEntity.class, typeAccesses = TypeAccess.DECLARED_CLASSES)
+ @MyBatisResourcesScan(reflectionTypePackages = "org.mybatis.spring.nativex.entity", reflectionTypeSupperType = StandardEntity.class, typeAccesses = MemberCategory.DECLARED_CLASSES)
@Configuration
static class ConfigurationForScanReflectionTypeWithSuperType {
}
diff --git a/core/src/test/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessorTest.java b/core/src/test/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessorTest.java
index 4182842..2222b2c 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessorTest.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/MyBatisScannedResourcesNativeConfigurationProcessorTest.java
@@ -15,14 +15,10 @@
*/
package org.mybatis.spring.nativex;
-import static org.springframework.nativex.hint.TypeAccess.*;
-import static org.springframework.nativex.hint.TypeAccess.QUERY_PUBLIC_CONSTRUCTORS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.nativex.component.BarTypeHandler;
import org.mybatis.spring.nativex.component.FooTypeHandler;
@@ -30,35 +26,30 @@
import org.mybatis.spring.nativex.component2.AnyTypeHandler;
import org.mybatis.spring.nativex.entity.City;
import org.mybatis.spring.nativex.entity.Country;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.DefaultNativeReflectionEntry;
-import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
+import org.springframework.aot.generate.GenerationContext;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
+import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
+import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
-import org.springframework.nativex.hint.TypeAccess;
class MyBatisScannedResourcesNativeConfigurationProcessorTest {
- private static final TypeAccess[] DEFAULT_TYPE_ACCESSES = { PUBLIC_CONSTRUCTORS, PUBLIC_CLASSES, PUBLIC_FIELDS,
- PUBLIC_METHODS, DECLARED_CLASSES, DECLARED_CONSTRUCTORS, DECLARED_FIELDS, DECLARED_METHODS,
- QUERY_DECLARED_METHODS, QUERY_PUBLIC_METHODS, QUERY_DECLARED_CONSTRUCTORS, QUERY_PUBLIC_CONSTRUCTORS };
+ private static final MemberCategory[] DEFAULT_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 };
@Test
void empty() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
- NativeConfigurationRegistry registry = process(context.getDefaultListableBeanFactory());
- // reflection hint
- {
- Map, DefaultNativeReflectionEntry> entries = registry.reflection().reflectionEntries()
- .collect(Collectors.toMap(DefaultNativeReflectionEntry::getType, x -> x));
- Assertions.assertThat(entries).isEmpty();
- }
- // resource hint
- {
- Set resources = registry.resources().toResourcesDescriptor().getPatterns();
- Assertions.assertThat(resources).isEmpty();
- }
+ RuntimeHints hints = process(context.getDefaultListableBeanFactory());
+ assertThat(hints.reflection().typeHints()).isEmpty();
+ assertThat(hints.resources().resourcePatternHints()).isEmpty();
}
@Test
@@ -66,22 +57,21 @@ void one() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.registerBean(ConfigurationForOne.class);
context.refresh();
- NativeConfigurationRegistry registry = process(context.getDefaultListableBeanFactory());
+ RuntimeHints hints = process(context.getDefaultListableBeanFactory());
// reflection hint
{
- Map, DefaultNativeReflectionEntry> entries = registry.reflection().reflectionEntries()
- .collect(Collectors.toMap(DefaultNativeReflectionEntry::getType, x -> x));
- Assertions.assertThat(entries).hasSize(2);
- Assertions.assertThat(entries.get(City.class)).satisfies(x -> Assertions.assertThat(x.getAccess().toArray())
- .isEqualTo(new TypeAccess[] { PUBLIC_CONSTRUCTORS, PUBLIC_METHODS }));
- Assertions.assertThat(entries.get(Country.class)).satisfies(x -> Assertions.assertThat(x.getAccess().toArray())
- .isEqualTo(new TypeAccess[] { PUBLIC_CONSTRUCTORS, PUBLIC_METHODS }));
+ assertThat(hints.reflection().typeHints()).hasSize(2);
+ assertThat(RuntimeHintsPredicates.reflection().onType(City.class)
+ .withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS))
+ .accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(Country.class)
+ .withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS))
+ .accepts(hints);
}
// resource hint
{
- Set resources = registry.resources().toResourcesDescriptor().getPatterns();
- Assertions.assertThat(resources).containsExactlyInAnyOrder("mapper/sub1/BarMapper.xml",
- "mapper/sub1/FooMapper.xml");
+ assertThat(RuntimeHintsPredicates.resource().forResource("mapper/sub1/BarMapper.xml")).accepts(hints);
+ assertThat(RuntimeHintsPredicates.resource().forResource("mapper/sub1/FooMapper.xml")).accepts(hints);
}
}
@@ -90,49 +80,54 @@ void multi() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.registerBean(ConfigurationForMulti.class);
context.refresh();
- NativeConfigurationRegistry registry = process(context.getDefaultListableBeanFactory());
+ RuntimeHints hints = process(context.getDefaultListableBeanFactory());
// reflection hint
{
- Map, DefaultNativeReflectionEntry> entries = registry.reflection().reflectionEntries()
- .collect(Collectors.toMap(DefaultNativeReflectionEntry::getType, x -> x));
- Assertions.assertThat(entries).hasSize(6);
- Assertions.assertThat(entries.get(City.class)).satisfies(x -> Assertions.assertThat(x.getAccess().toArray())
- .isEqualTo(new TypeAccess[] { PUBLIC_CONSTRUCTORS, PUBLIC_METHODS }));
- Assertions.assertThat(entries.get(Country.class)).satisfies(x -> Assertions.assertThat(x.getAccess().toArray())
- .isEqualTo(new TypeAccess[] { PUBLIC_CONSTRUCTORS, PUBLIC_METHODS }));
- Assertions.assertThat(entries.get(FooTypeHandler.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(DEFAULT_TYPE_ACCESSES));
- Assertions.assertThat(entries.get(BarTypeHandler.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(DEFAULT_TYPE_ACCESSES));
- Assertions.assertThat(entries.get(AnyTypeHandler.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(DEFAULT_TYPE_ACCESSES));
- Assertions.assertThat(entries.get(TypeHandlers.InnerTypeHandler.class))
- .satisfies(x -> Assertions.assertThat(x.getAccess().toArray()).isEqualTo(DEFAULT_TYPE_ACCESSES));
+ assertThat(hints.reflection().typeHints()).hasSize(6);
+ assertThat(RuntimeHintsPredicates.reflection().onType(City.class)
+ .withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS))
+ .accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(Country.class)
+ .withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS))
+ .accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(FooTypeHandler.class)
+ .withMemberCategories(DEFAULT_MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(BarTypeHandler.class)
+ .withMemberCategories(DEFAULT_MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(AnyTypeHandler.class)
+ .withMemberCategories(DEFAULT_MEMBER_CATEGORIES)).accepts(hints);
+ assertThat(RuntimeHintsPredicates.reflection().onType(TypeHandlers.InnerTypeHandler.class)
+ .withMemberCategories(DEFAULT_MEMBER_CATEGORIES)).accepts(hints);
}
// resource hint
{
- Set resources = registry.resources().toResourcesDescriptor().getPatterns();
- Assertions.assertThat(resources).containsExactlyInAnyOrder("mapper/sub1/BarMapper.xml",
- "mapper/sub1/FooMapper.xml", "mapper/sub2/AnyMapper.xml");
+ assertThat(RuntimeHintsPredicates.resource().forResource("mapper/sub1/BarMapper.xml")).accepts(hints);
+ assertThat(RuntimeHintsPredicates.resource().forResource("mapper/sub1/FooMapper.xml")).accepts(hints);
+ assertThat(RuntimeHintsPredicates.resource().forResource("mapper/sub2/AnyMapper.xml")).accepts(hints);
}
-
}
- private NativeConfigurationRegistry process(DefaultListableBeanFactory beanFactory) {
- NativeConfigurationRegistry registry = new NativeConfigurationRegistry();
- new MyBatisScannedResourcesNativeConfigurationProcessor().process(beanFactory, registry);
- return registry;
+ private RuntimeHints process(DefaultListableBeanFactory beanFactory) {
+ RuntimeHints hints = new RuntimeHints();
+ GenerationContext generationContext = mock(GenerationContext.class);
+ when(generationContext.getRuntimeHints()).thenReturn(hints);
+ BeanFactoryInitializationAotContribution contribution = new MyBatisScannedResourcesNativeConfigurationProcessor()
+ .processAheadOfTime(beanFactory);
+ if (contribution != null) {
+ contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));
+ }
+ return hints;
}
@MyBatisResourcesScan(typeAliasesPackages = "org.mybatis.spring.nativex.entity", mapperLocationPatterns = "mapper/sub1/*.*", typeAccesses = {
- TypeAccess.PUBLIC_CONSTRUCTORS, TypeAccess.PUBLIC_METHODS })
+ MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS })
@Configuration
static class ConfigurationForOne {
}
@MyBatisResourcesScan(typeAliasesPackages = "org.mybatis.spring.nativex.entity", typeAccesses = {
- TypeAccess.PUBLIC_CONSTRUCTORS, TypeAccess.PUBLIC_METHODS })
+ MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS })
@MyBatisResourcesScan(typeHandlerPackages = "org.mybatis.spring.nativex.component")
@MyBatisResourcesScan(mapperLocationPatterns = "mapper/sub1/*.*")
@MyBatisResourcesScan(reflectionTypePackages = "org.mybatis.spring.nativex.component2")
diff --git a/core/src/test/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfigurationTest.java b/core/src/test/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfigurationTest.java
index 99a6a39..c899c04 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfigurationTest.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/autoconfigure/MyBatisSpringNativeAutoConfigurationTest.java
@@ -22,6 +22,7 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.nativex.MyBatisResourcesScan;
import org.mybatis.spring.nativex.component.AbstractTypeHandler;
import org.mybatis.spring.nativex.component.BarService;
@@ -31,6 +32,9 @@
import org.mybatis.spring.nativex.component2.AnyTypeHandler;
import org.mybatis.spring.nativex.entity.City;
import org.mybatis.spring.nativex.entity.Country;
+import org.mybatis.spring.nativex.mapper.SampleMapper;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -133,6 +137,21 @@ void multi() {
}
}
+ @Test
+ void clearMapperFactoryBeanConstructorArguments() {
+ DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
+ beanFactory.registerBeanDefinition("sampleMapper",
+ BeanDefinitionBuilder.rootBeanDefinition(MapperFactoryBean.class)
+ .addConstructorArgValue(SampleMapper.class.getName())
+ .addPropertyValue("mapperInterface", SampleMapper.class).getBeanDefinition());
+ Assertions.assertThat(beanFactory.getBeanDefinition("sampleMapper").getConstructorArgumentValues().isEmpty())
+ .isFalse();
+ new MyBatisSpringNativeAutoConfiguration().mybatisMapperFactoryBeanDefinitionPostProcessor()
+ .postProcessBeanFactory(beanFactory);
+ Assertions.assertThat(beanFactory.getBeanDefinition("sampleMapper").getConstructorArgumentValues().isEmpty())
+ .isTrue();
+ }
+
@EnableAutoConfiguration
@Configuration
static class EmptyConfiguration {
diff --git a/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample2Mapper.java b/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample2Mapper.java
index 3f2e1ed..7989785 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample2Mapper.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample2Mapper.java
@@ -15,5 +15,5 @@
*/
package org.mybatis.spring.nativex.mapper;
-public class Sample2Mapper {
+public interface Sample2Mapper {
}
diff --git a/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample3Mapper.java b/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample3Mapper.java
index b5c3fb9..ec200ae 100644
--- a/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample3Mapper.java
+++ b/core/src/test/java/org/mybatis/spring/nativex/mapper/Sample3Mapper.java
@@ -15,5 +15,5 @@
*/
package org.mybatis.spring.nativex.mapper;
-public class Sample3Mapper {
+public interface Sample3Mapper {
}
diff --git a/extensions/pom.xml b/extensions/pom.xml
index a94470c..10be0b9 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -58,20 +58,15 @@
true