Java 番石榴ImmutableBiMap变为LinkedHashMap并导致Spring自动布线错误

Java 番石榴ImmutableBiMap变为LinkedHashMap并导致Spring自动布线错误,java,spring,guava,Java,Spring,Guava,我有两个简单的SpringBean填充的ImmutableBiMap 操作系统:Manjaro Linux JDK版本:1.8.0.102 Oracle Spring版本:4.3.4.0从发布 <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>Athens-SR1</version> 如下屏幕所示,当Sp

我有两个简单的SpringBean填充的ImmutableBiMap

操作系统:Manjaro Linux JDK版本:1.8.0.102 Oracle Spring版本:4.3.4.0从发布

<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Athens-SR1</version>
如下屏幕所示,当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;
    }
}
@组件
@Slf4j
公共类测试控制{
专用最终BiMap自动机;
@自动连线
公共测试控制(BiMap自动机){
this.automatons=自动机;
log.info(“automatons={}”,automatons.keySet());
}
}
@配置
公共类文本上下文{
公共静态void main(字符串[]args){
ApplicationContext上下文=新注释ConfigApplicationContext(
TextContext.class,
TestControl.class
);
BiMap bean=context.getBean(BiMap.class);
}
@豆子
BiMap自动机(){
返回不可变的BIMAP.of(
“细胞自动机”,细胞自动机(),
“蒙特卡罗自动机”,蒙特卡罗自动机();
}
@豆子
整型纤维素Automaton(){
返回6;
}
@豆子
整数Montecarloutomaton(){
返回5;
}
}

除非Spring中有一个巨大的bug(我对此表示怀疑),否则这一定是人为/编辑错误

我重新创建了一个比较简单的示例,与我刚才使用的字符串、整数、Long和Boolean相同,因为我没有您的类型-这个简单的示例很有效

LinkedHashMap不是BiMap,因此如果选择它作为autowire候选,它将是一个bug。听起来源代码和编译后的代码几乎不同步,您是否尝试删除生成文件夹并重新生成

如果重建没有帮助,解决这个问题的唯一方法就是进行老式的调试

  • 在LinkedHashMaps构造函数中放置一个断点,看看它是在哪里构造的,它与您的bean有什么关系吗
  • 在org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor中设置一个条件断点(因此只有当beanName.equals(“AutomationTypeSettingsControl”)时才停止),并逐步执行该方法,以便查看spring如何找到autowire候选对象
  • 制作一个失败的最简单的独立示例,将其放在Github上并发布一个链接,然后其他人可能会帮助您进行调试
  • 观察:我在上个月读了很多StackOverflow帖子,看起来普通开发人员在调试第三方代码方面不是很好。事实上,你可以从调试其他人的代码中学到很多东西,特别是spring框架代码,考虑到这个问题,我发现它很容易阅读绿萍


    编辑正如另一个答案中所述,这是Spring的一个限制。也就是说,我最终复制了错误,并通过Spring代码在大约1小时内找到了这种行为的确切代码。我觉得许多开发人员忽视了调试作为一项软件规程。对我来说,这是最重要的一项纪律,因为您可能大部分时间都在处理代码,所以您不是自己编写的。

    除非Spring中有一个巨大的bug(我怀疑),否则这一定是人为/编辑错误

    我重新创建了一个比较简单的示例,与我刚才使用的字符串、整数、Long和Boolean相同,因为我没有您的类型-这个简单的示例很有效

    LinkedHashMap不是BiMap,因此如果选择它作为autowire候选对象,它将是一个错误。听起来源代码和编译的代码几乎不同步,您是否尝试删除生成文件夹并重新生成

    如果重建没有帮助,解决这个问题的唯一方法就是进行老式的调试

  • 在LinkedHashMaps构造函数中放置一个断点,看看它是在哪里构造的,它与您的bean有什么关系吗
  • 在org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor中设置一个条件断点(因此只有当beanName.equals(“AutomationTypeSettingsControl”)时才停止),并逐步执行该方法,以便查看spring如何找到autowire候选对象
  • 制作一个失败的最简单的独立示例,将其放在Github上并发布一个链接,然后其他人可能会帮助您进行调试
  • 观察:我在上个月读了很多StackOverflow帖子,看起来普通开发人员在调试第三方代码方面不是很好。事实上,你可以从调试其他人的代码中学到很多东西,特别是spring框架代码,考虑到这个问题,我发现它很容易阅读绿萍

    编辑正如另一个答案中所述,这是Spring的一个限制。也就是说,我最终复制了错误,并通过Spring代码在大约1小时内找到了这种行为的确切代码。我觉得许多开发人员忽视了调试作为一项软件规程。对我来说,这是最重要的一项纪律,因为你可能大部分时间都在处理代码,而不是自己编写的。

    这是一个副作用

    即使键入的
    Map
    s也可以自动连接,只要所需的键类型为
    String
    Map
    值将包含预期类型的所有bean, 键将包含相应的bean名称:[……]

    A是一张
    地图

    Spring并没有试图将您的
    自动机
    bean注入
    TestControl
    。相反,它试图找到所有类型为
    Integer
    的bean作为值,将它们收集到
    映射中(
    LinkedHashMap
    作为选择的实现),并将它们与bean名称关联作为键

    在这种情况下,它会失败,因为构造函数需要一个
    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;
        }
    }
    
    @Autowired()
    public TestControl(@Qualifier(value = "automatons") BiMap<String, Integer> automatons) {
        this.automatons = automatons;
    }
    
    @Resource(name = "automatons") // if you don't specify the name element, Spring will try to use the field name
    private BiMap<String, Integer> automatons;