Announcement Announcement Module
Collapse

JavaConfig forum decommissioned in favor of Core Container

As described at

http://static.springsource.org/sprin...fig/README.TXT

key features of the Spring JavaConfig project have been migrated into the core Spring Framework as of version 3.0.

Please see the Spring 3.0 documentation on @Configuration and @Bean support:

http://static.springsource.org/sprin...tml#beans-java

For any questions related to @Configuration classes and @Bean methods in Spring 3.0, please post in the dedicated 'Core Container' forum at

http://forum.springsource.org/forumdisplay.php?f=26
See more
See less
@ImportXml using value from @ExternalValue Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @ImportXml using value from @ExternalValue

    Hello,
    I am trying to mix configuration styles XML and JavaConfig so that I can dynamically import a different XML beans definition file depending on the value of a property.

    The basic idea is this:

    Code:
    @Configuration
    @AnnotationDrivenConfig
    @PropertiesValueSource(locations={"classpath:storefront.properties"})
    @ImportXml(locations={"[VALUE of storefrontXml]"})
    public class StoreFrontConfig {
    	@ExternalValue("storefront.xml") String storefrontXml;
    	
    	protected Logger logger = Logger.getLogger(this.getClass());
    	
    	@PostConstruct
    	public void init() {
    		logger.info("storefrontXml=" + storefrontXml);
    	}
    	
    }
    Logically:
    1. Set the value of storefrontXml from the external properties file
    2. use the value of storefrontXml field inside the @ImportXml annotation to import the appropriate XML beans definition.

    Is this possible?

    Thx in advance!

    -Ed

  • #2
    Hi Ed,

    Unfortunately, what you're trying to do is not possible, for several reasons. Here's a possible workaround, however:

    Wherever you're bootstrapping JavaConfigApplicationContext:
    Code:
    public static void main(String[] args) {
        String xmlFile = args[0];
        ClassPathXmlApplicationContext xmlParent = new ClassPathXmlApplicationContext(xmlFile);
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(xmlParent);
        // ...
    }
    All the XML-defined beans will be available to all the JavaConfig-defined beans, and you can dynamically determine which XML file to use.

    Hope this helps!

    Comment


    • #3
      Thanks Chris,

      I am actually trying to bootstrap the JavaConfigApplicationContext from an existing web application by including the bean inside my applicationContext.xml:

      Code:
      <bean class="org.springframework.config.java.process.ConfigurationPostProcessor"/>
      I was then hoping to annotate a couple of classes with @Configuration to do the dynamic imports mentioned in my original post. However, I can't seem to get past this exception on startup in Tomcat 6.0.14:

      Code:
      2009-03-30 11:09:04,984 ERROR [org.springframework.web.context.ContextLoader] - <Context initialization failed>
      java.lang.NullPointerException
              at org.springframework.util.ClassUtils.convertClassNameToResourcePath(ClassUtils.java:754)
              at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:68)
              at org.springframework.config.java.process.ConfigurationBeanDefinitionDecoratingBeanFactoryPostProcessor.isConfigClass(ConfigurationBeanDefini
      tionDecoratingBeanFactoryPostProcessor.java:63)
              at org.springframework.config.java.process.ConfigurationBeanDefinitionDecoratingBeanFactoryPostProcessor.postProcessBeanFactory(ConfigurationB
      eanDefinitionDecoratingBeanFactoryPostProcessor.java:48)
              at org.springframework.config.java.process.ConfigurationPostProcessor.postProcessBeanFactory(ConfigurationPostProcessor.java:42)
              at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:553)
              at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:536)
              at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:362)
              at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
              at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
              at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
              at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3830)
              at org.apache.catalina.core.StandardContext.start(StandardContext.java:4337)
              at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
              at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
              at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
              at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:825)
              at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:714)
              at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:490)
              at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
              at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
              at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
              at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
              at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
              at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
              at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
              at org.apache.catalina.core.StandardService.start(StandardService.java:516)
              at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
              at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
              at java.lang.reflect.Method.invoke(Method.java:597)
              at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
      I saw an old JIRA relating to this issue, but don't see a way forward. Being a complete newb to JavaConfig I'm sure I am missing something basic. Do I need to bootstrap the context from my web.xml? If so, can I use both the regular WebApplicationContext side-by-side with this one?

      Thanks again for your reply.

      -Ed

      Comment


      • #4
        Ed,

        Take a look at the reference docs' section on bootstrapping in a web app:

        http://static.springframework.org/sp...l/ch03s02.html

        - C

        Comment


        • #5
          Thanks for the clarification & your patience...

          Just to make sure I am understanding you and the docs correctly:

          Inside my web.xml I EITHER use the usual implicit loading of the XmlApplicationContext OR the JavaConfigWebApplicationContext configuration to which you referred me.

          If I were to use the latter, then I could have one/many @Configuration classes in which I could import all my web application's existing xml configuration. Inside at least one of those existing XML configuration files I would then need to add the post processor bean:

          Code:
          <bean class="org.springframework.config.java.process.ConfigurationPostProcessor"/>
          In addition I could then pursue the solution for a "conditional import" that you outlined above.

          Does that sound about right?

          Thx,

          -Ed

          Comment


          • #6
            If you're bootstrapping via a JavaConfig[Web]ApplicationContext, there's no need at all for declaring a ConfigurationPostProcessor. CPP is only necessary if you're bootstrapping via ClassPathXmlApplicationContext or some other non-JavaConfig-aware ApplicationContext implementation.

            Yes, your understanding is correct, that it's an either/or thing in web.xml. Either bootstrap with the implicit XmlWebApplicationContext or explicitly with JavaConfigWebApplicationContext.

            The 'conditional import' workaround that I detailed would only really work if you're programmatically creating your JavaConfigApplicationContext. In web.xml, you're creating it declaratively, and so there's no real way to 'decide' which beans xml files you want to import.

            Comment


            • #7
              Thanks Chris. Clear now :-)

              Given that I am working with an existing app, I may investigate alternatives for my underlying problem.

              Comment

              Working...
              X