Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String 的解决办法

Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String 的解决办法
问题概述

关于这个问题,博主是在跑单元测试的时候遇到的,本篇文章可能较长,如果只想解决问题本身,可只关注结果,跳过过程!

环境:

spring-boot 3.2.1
jdk 17

报错:“ Caused by: java.lang.IllegalArgumentException: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String

莫名的参数类型错误,

如下图:

具体信息如下:

java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@4b74b35 testClass = ...ApplicationTests, locations = [], classes = [com...Application], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@7bd4937b, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@741a8937, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@2ea41516, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@4b0d79fc, org.springframework.boot.test.context.SpringBootTestAnnotation@4a86e4f0], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:191) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:130) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:163) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) at java.base/java.util.Optional.orElseGet(Optional.java:364) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Caused by: java.lang.IllegalArgumentException: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getTypeForFactoryBeanFromAttributes(FactoryBeanRegistrySupport.java:86) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:836) at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:620) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:575) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:534) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:138) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:606) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:464) at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137) at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1458) at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:552) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) ... 17 more Process finished with exit code -1 

解决办法

根据错误信息,参数类型错误

参考【mybatis-spring-issues 855】得知:

在 Spring Boot 3.0后的 版本中FactoryBeanRegistrySupport#getTypeForFactoryBeanFromAttributes方法已变更,如果 factoryBeanObjectType 不是 ResolvableType 或 Class 类型会抛出 IllegalArgumentException 异常。

此时因为 factoryBeanObjectType 是 String 类型,不符合条件而抛出异常。

如下图:

项目中使用的 mybatis-plus-boot-starter 是当前最新版本 3.5.5,但 mybatis-spring 为2.1.2 

如下图:

但版本已不兼容,

兼容对照表:

MyBatis-Spring-Boot-Starter、MyBatis-Spring、Spring Boot、Java 版本兼容对照如下表:

好了,问题分析清楚了,

可以解决问题了,

第一步:排除 mybatis-plus-boot-starter 中的旧版本 mybatis-spring

 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> <exclusions> <exclusion> <artifactId>mybatis-spring</artifactId> <groupId>org.mybatis</groupId> </exclusion> </exclusions> </dependency>

第二步:引入 mybatis-spring 3.0.3 版本

 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency>

完整内容:

 <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> <exclusions> <exclusion> <artifactId>mybatis-spring</artifactId> <groupId>org.mybatis</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency>

第三步:测试

再次跑单元测试,就成功执行了,如下图:

源码扩展,可忽略:

Springboot Version 3.2.0-M2,spring-boot-starter 3.0.2 在这个版本中,FactoryBeanRegistrySupport.getTypeForFactoryBeanFromAttributes()方法已经改变,当“factoryBeanObjectType”不是ResolvableType或者Class类型时抛出一个IllegalArgumentException,

如下图:

org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getTypeForFactoryBeanFromAttributes

通过检查FactoryBean的属性来确定FactoryBean的bean类型
从ResolvableType中提取属性或者ResolvableType.NONE,
很遗憾,从ResolvableType中未找到FactoryBean的属性或者ResolvableType.NONE,

但是在 org.mybatis.spring.mapper.ClassPathMapperScanner.processBeanDefinitions()方法(第254行)设置一了个字符串类型beanClassName,

如下图:

在 mybatis-spring-3.0.3 通过反射创建一个Class类:

 String beanClassName = definition.getBeanClassName(); LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface"); // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59 try { Class<?> beanClass = Resources.classForName(beanClassName); // Attribute for MockitoPostProcessor // https://github.com/mybatis/spring-boot-starter/issues/475 definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, beanClass); // for spring-native definition.getPropertyValues().add("mapperInterface", beanClass); } catch (ClassNotFoundException ignore) { // ignore }

如下图:

 到这里,就可以成功识别到Class类型了:

自此,问题就解决了,项目的单元测试模块跑通了,如下图:

其它补充:


好了,关于 Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String 的解决办法  就写到这儿了,如果还有什么疑问或遇到什么问题欢迎扫码提问,也可以给我留言哦,我会一一详细的解答的。 
歇后语:“ 共同学习,共同进步 ”,也希望大家多多关注CSND的IT社区。


作       者:华    仔
联系作者:[email protected]
来        源:ZEEKLOG (Chinese Software Developer Network)
原        文:https://blog.ZEEKLOG.net/Hello_World_QWP/article/details/135771075
版权声明:本文为博主原创文章,请在转载时务必注明博文出处!