Announcement Announcement Module
Collapse
No announcement yet.
@ContextConfiguration Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @ContextConfiguration

    Hi everyone

    Probably a simple question, so here we go: when writing unit tests, I can use @ContextConfiguration to set my spring context and have the load time weaver autowire my @Configurable classes' fields.

    However, running the main program like this:

    Code:
    @ContextConfiguration(locations = {"classpath:/com/emc/config/spring.cfg.xml"})
    @Configurable
    public class Hello {
    	@Autowired
    	private HelloService service;
    	
    	public void sayHello() {
    		service.sayHello("Tom");
    	}
    	
    	public static void main(String[] args) {
    		Hello hello = new Hello();
    		hello.sayHello();
    	}
    }
    does not seem to work. Instead, I'm continually being advised to start my program like this:

    Code:
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/emc/config/spring.cfg.xml");
    System.out.println(((HelloService)ctx.getBean("HelloService")).sayHello("Tom"));
    Personally, however, I find the other way using @ContextConfiguration much more elegant. How can such an annotation based context load be achieved in this situation?

    Thank you in advance for any reply.

    Best regards
    Kessi

  • #2
    You don't and you will never be able to do so. Not without changing the way classes are loaded (you will need something that knows what to do with the @ContextConfiguration annotation). You would need AOP for that, next to that you wouldn't want the context to be initialized all the time.

    You will need to create a ApplicationContext and you need to configure AspectJ to do loadtime weaving (add a java agent to the classpath) to make the @Configurable work. That way your new is working but you will first need an ApplicationContext which the Aspect can use for autowiring.

    P.S. Please next time don't post multiple times!

    Comment


    • #3
      In addition to what Martin pointed out, @ContextConfiguration is part of the the Spring TestContext Framework. As such it is packaged in the "org.springframework.test" module and should never be used in production code.

      - Sam

      Comment


      • #4
        I do agree with the original poster that using @ContextConfiguration could be an easier way to fire up an application. As has been told there is of course no way to start Spring without calling Spring in your main method.

        But it would be almost trivial for the people who programmed the JUnit test runner to implement something simple like a "SpringStarter" to make it work, so we can start the program by doing something like:

        Code:
        	public static void main(String[] args) {
        		SpringStarter.start();
        	}

        Comment


        • #5
          Originally posted by SlowStrider View Post
          But it would be almost trivial for the people who programmed the JUnit test runner to implement something simple like a "SpringStarter" to make it work, so we can start the program by doing something like:
          Is the following not trivial enough for you?

          Code:
          public static void main(String[] args) {
          	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml");
          	Service service = (Service) ctx.getBean("service");
          }
          FYI: I am the person "who programmed the JUnit test runner".

          Regards,

          Sam

          p.s. you may be interested in some of the new Java-based container configuration support (i.e., annotation-driven configuration options) that have been introduced in Spring 3.0 (e.g., @Configuration, @Bean, @Lazy, @Import, etc.). These features have been incorporated into the core Spring Framework from the Spring JavaConfig project.

          Comment


          • #6
            Well now you mention it, it doesn't matter much in terms of lines of code , I don't know what I was thinking... Although it would provide a slightly more consistent way of starting either a unit test or a main program.

            My example would also be a bit longer: I forgot to pass in the Class to my hypothetical "SpringStarter"; it would be handy if it knows where to find the @ContextConfiguration.

            Comment


            • #7
              Originally posted by SlowStrider View Post
              My example would also be a bit longer: I forgot to pass in the Class to my hypothetical "SpringStarter"; it would be handy if it knows where to find the @ContextConfiguration.
              Like I alluded to before, it really sounds like you might be interested in Spring JavaConfig. Consider the following example taken from the JavaConfig Reference Manual:

              Code:
              JavaConfigApplicationContext context = new JavaConfigApplicationContext(AppConfig.class);
              Service service = context.getBean(Service.class);
              - Sam

              Comment


              • #8
                A minor note that if you do choose to go with the ApplicationContext route suggested above, the name of this class has changed as of Spring 3. It is now called ConfigurationClassApplicationContext.

                Code:
                ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(AppConfig.class);
                Service service = context.getBean(Service.class);

                Comment


                • #9
                  Thank you for pointing to that I will have a look at it. At least the type-safety is nice.

                  Comment


                  • #10
                    Will ApplicationContextAware interface help this situation

                    I just formatted the original code posted to suit it to be a test scenario. The following solution works for me. I use it especially to infer to beans for test that have been configured in traditional xml configuration.
                    Code:
                    @RunWith(SpringJUnit4ClassRunner.class)
                    @ContextConfiguration(locations = {"classpath:/com/emc/config/spring.cfg.xml"})
                    @Configurable
                    public class HelloServiceTest implements ApplicationContextAware{
                    
                    	private ApplicationContext applicationContext;
                    	
                    	private HelloService service;
                    	
                    	@Test
                    	public void testHello() {
                    		service = (HelloService) applicationContext.getBean("HelloService");
                    		service.sayHello("Tom");
                    	}
                    	
                    	public void setApplicationContext(ApplicationContext argApplicationContext) throws BeansException {
                    		applicationContext = argApplicationContext;
                    	}
                    }

                    Comment


                    • #11
                      Hi Sudhcha,

                      FYI: your configuration is overkill. You should practically never need to implement ApplicationContextAware in a test class. Instead, you should just autowire your test dependencies -- you should not look them up manually via ApplicationContext.getBean(...).

                      In addition, @Configurable has no place in a test class!

                      Thus, your example should be rewritten as follows (for Spring 3.0+):

                      Code:
                      @RunWith(SpringJUnit4ClassRunner.class)
                      @ContextConfiguration("/com/emc/config/spring.cfg.xml")
                      public class HelloServiceTest {
                      
                      	@Autowired
                      	private HelloService helloService;
                      	
                      	@Test
                      	public void testHello() {
                      		helloService.sayHello("Tom");
                      	}
                      }
                      Cheers,

                      Sam

                      Comment


                      • #12
                        Proposed Spring Enhancement

                        In order to address this issue, I have created https://jira.springsource.org/browse/SPR-9044. If you like the proposed approach, please vote for it.

                        Comment

                        Working...
                        X