Announcement Announcement Module
Collapse
No announcement yet.
Spring 3.1 - AnnotationConfigWebApplicationContext: scan vs. register method Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring 3.1 - AnnotationConfigWebApplicationContext: scan vs. register method

    Hi,

    I was playing around with the new java-config features of Spring 3.1 and I stumbled across what is either a bug or a misunderstanding of the supported behavior.

    Assume the following class definitions:

    Code:
    package com.foo;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class ComponentA {
    
    }

    Code:
    package com.bar;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class ComponentA {
    
    }
    Two classes, same simple name (same bean name), different packages. Let's also pretend that packages com.foo and com.bar also contain a bunch of different components. In a single context, I want the sum of all components defined in packages com.foo and com.bar, knowing that their would be a clash for ComponentA because it is defined in the two packages, so I tried the following:

    Code:
    package com.potato;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.FilterType;
    
    @Configuration
    @ComponentScan(basePackages = {"com.foo", "com.bar"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = com.foo.ComponentA.class)})
    public class TestConfig {
    
    }


    Code:
    public class Main {
    
    	public static void main(String[] args) {
    
    		AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    		rootContext.scan("com.potato");
    		rootContext.refresh();
    		rootContext.close();
    	}
    
    }
    This throws the following exception

    Code:
    Exception in thread "main" org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'componentA' for bean class [com.bar.ComponentA] conflicts with existing, non-compatible bean definition of same name and class [com.foo.ComponentA]
    But, if I simply replace the usage of the "scan" method for the "register" method on the context, it works:

    Code:
    public class Main {
    
    	public static void main(String[] args) {
    
    		AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    		rootContext.register(com.potato.TestConfig.class);
    		rootContext.refresh();
    		rootContext.close();
    	}
    
    }
    The reason I am using the "scan" method is because the com.potato package contains other configuration classes that I want loaded, as opposed to registering them one by one. Is this supposed to work? I put a breakpoint in "parse" method of the org.springframework.context.annotation.ComponentSc anAnnotationParser class where it seems to register the exclude filters, and when I register my config classes using the "scan" method of the AnnotationConfigWebApplicationContext, it never stops there (it does when I use the "register" method though). I know the work around is simply to register my config classes one by one, but it would be nice that it worked both ways.

    Thank you.

  • #2
    The scan method scans for @Components and not only for @Configuration (basically you could use it to scan for your components without having a single @Configuration class), so it might be that something else is also doing a @ComponentScan (if you have other configuration classes).

    Comment


    • #3
      Thanks for your reply. No, I don't have other classes. My package com.potato only contains a single class (for the moment). I debugged more and looked at the loadBeanDefinitions method of the AnnotationConfigWebApplicationContext. When registering a class through the register method, or when an entry of the configLocation property points to a class as opposed to a package, it uses the AnnotatedBeanDefinitionReader to process the specified class. When using the scan method or when an entry of the configLocation property points to a package, it uses the ClassPathBeanDefinitionScanner. The javadoc of the AnnotatedBeanDefinitionReader says "This is an alternative to ClassPathBeanDefinitionScanner, applying the same resolution of annotations but for explicitly registered classes only." Reading this, seems to me that what I was trying to do is right and there shouldn't be any difference in behavior whether you process a single class or a package name. The scenario that I outlined above shows that it's not the case. Thanks for your help. I'll open an issue in JIRA.

      Comment


      • #4
        The issue that Yannick opened is https://jira.springsource.org/browse/SPR-9100. I've just closed this as a duplicate of https://jira.springsource.org/browse/SPR-9031, which is resolved for Spring 3.1.1. See resolution comments there for complete details.

        Comment


        • #5
          Thanks! Sorry for the duplicate. I had seen the other one but wasn't entirely sure it was the exact same cause or that one would fix the other. I'll give it a go in 3.1.1.

          Comment

          Working...
          X