我有ImmutableBiMap填充了2个简单的Spring bean。
操作系统:Manjaro Linux JDK版本:1.8.0.102 Oracle 春季版:4.3.4.RELEASE来自
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Athens-SR1</version>
创建上下文抛出:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [...]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
如下面的屏幕所示,当Spring抛出异常时,BeanUtil参数是LinkedHashMap而不是BiMap。
最小,完整且可验证的示例:
@Component
@Slf4j
public class TestControl {
private final BiMap<String, Integer> automatons;
@Autowired
public TestControl(BiMap<String, Integer> automatons) {
this.automatons = automatons;
log.info("automatons={}", automatons.keySet());
}
}
@Configuration
public class TextContext {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(
TextContext.class,
TestControl.class
);
BiMap bean = context.getBean(BiMap.class);
}
@Bean
BiMap<String, Integer> automatons() {
return ImmutableBiMap.of(
"Cellular Automaton", cellularAutomaton(),
"Monte Carlo Automaton", monteCarloAutomaton());
}
@Bean
Integer cellularAutomaton() {
return 6;
}
@Bean
Integer monteCarloAutomaton() {
return 5;
}
}
答案 0 :(得分:4)
这是how Spring handles some container types的副作用。
只要预期的密钥类型是,即使是键入的
Map
也可以自动装配String
。Map
值将包含预期类型的所有bean, 并且键将包含相应的bean名称:[...]
BiMap
是Map
。
Spring并没有尝试将automatons
bean注入TestControl
。相反,它试图找到类型Integer
的所有bean作为值,将它们收集到Map
(LinkedHashMap
作为选择的实现),并将它们与bean名称关联作为关键
在这种情况下,它失败,因为构造函数需要BiMap
。
一种解决方案是按名称注入。
@Autowired()
public TestControl(@Qualifier(value = "automatons") BiMap<String, Integer> automatons) {
this.automatons = automatons;
}
通过使用名称指定限定符,Spring将尝试查找名为automatons
的bean(具有适当的类型)。
如果您不太依赖final
实例字段,也可以使用@Resource
@Resource(name = "automatons") // if you don't specify the name element, Spring will try to use the field name
private BiMap<String, Integer> automatons;
对于原因,这只能工作4.3 +。
对于自身定义为集合/映射或数组的bean 类型,
@Resource
是一个很好的解决方案,指的是具体的 集合或数组bean按唯一名称。也就是说,截至4.3, 可以通过Spring匹配集合/映射和数组类型@Autowired
类型匹配算法也是如此,只要元素 类型信息保存在@Bean
返回类型签名或 集合继承层次结构。在这种情况下,限定符值可以 用于在相同类型的集合中进行选择,如中所述 前一段。
我会对你在4.3之前看到的行为感到满意,但这似乎是Map
的错误。 (List
和数组类型的行为正确。)
我已经打开SPR-15117来跟踪它,现在已经解决了(2天营业额,哇!)。
答案 1 :(得分:1)
除非Spring中存在巨大的错误(我怀疑),否则这必定是人/编辑错误。
我重新创建了一个更简单的例子,同样的基础知识我刚刚使用了String,Integer,Long和Boolean,因为我没有你的类型 - 这个简单的例子可以运行。
LinkedHashMap不是BiMap,如果它被选为autowire候选者,那将是一个错误。它几乎听起来像源代码和已编译的代码不同步,您是否尝试删除构建文件夹并重建?
如果重建没有帮助,解决这个问题的唯一方法就是老式调试。
观察:我在上个月看过很多StackOverflow帖子,看起来平均开发人员调试第三方代码不是很好。实际上,你可以从调试其他人的代码中学到很多东西,尤其是spring框架代码,考虑到它正在解决的问题,我觉得这很容易阅读。
编辑这在Spring中是一个限制,如另一个答案中所述。这就是说我最终重现错误并通过Spring代码读取,以便在大约1小时内找到此行为的确切代码。我觉得很多开发人员都把调试视为软件学科。对我而言,它是最重要的学科之一,因为你可能花了大部分时间来处理你自己没有写过的代码。