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
Dynamic configuration from Java classes to Java Config Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Dynamic configuration from Java classes to Java Config

    I have some configuration which are set by the users using java class. I would like to pass on these configuration to Spring Java Config classes. How do I achieve this in SJC?

    For instance, the database configuration is set in the Configuration java class (custom code). I would like to pull the database configuration from this custom class and dynamically pass these parameters to DataSourceConfiguration (SJC).

    Appreciate any insight into this.

  • #2
    I believe you've gotten this question answered via other channels - is that right?

    Comment


    • #3
      Chris,

      SystemPropertiesValueSource does not really solve my problem as my application could run within a J2SE/J2EE container, as I do not have control over other libraries within the same JVM could possibly override the system properties.

      So, I am looking for some kind of setters on these configuration objects which could be invoked just after context initialization.

      Basically, I should be able to set some of the database configuration properties at runtime without using any of the existing properties resolvers (System, Environment).

      Code:
              JavaConfigApplicationContext context = new JavaConfigApplicationContext(ApplicationConfiguration.class);
              Configuration configuration = new Configuration();//my application config class
              configuration.setDatabaseType("MYSQL");
              configuration.setDriver("com.mysql.jdbc.Driver");
              configuration.setUrl("jdbc:mysql://localhost:3306/sjc");
              configuration.setUsername("root");
              configuration.setPassword("mysql");
              overrideConfiguration(configuration);//this should somehow override the configuration originally initialized by the application context
              DataSource ds = context.getBean(BasicDataSource.class);
              Connection conn = ds.getConnection();
      Is it possible to achieve something like this in SJC?

      Appreciate your clarification.

      Thanks!
      Arul

      Comment


      • #4
        Chris,

        I was able to resolve this issue after going through some of the system tests.

        Btw, did you had a chance to look in to the code which I submitted for http://jira.springframework.org/browse/SJC-150?

        -Arul

        Comment


        • #5
          Re: SJC-150 - not yet, but I haven't forgotten about it. Thanks again for submitting.

          Comment


          • #6
            Overriding configuration after context creation

            Hi Chris,

            I have the following test case which fails to override the bean configuration after context creation. Could you please correct me if I am missing something in my configuration?

            Code:
            import static junit.framework.Assert.assertEquals;
            import org.junit.Test;
            import org.springframework.config.java.annotation.Bean;
            import org.springframework.config.java.annotation.Configuration;
            import org.springframework.config.java.context.JavaConfigApplicationContext;
            import org.springframework.jdbc.datasource.DriverManagerDataSource;
            
            import javax.sql.DataSource;
            import java.sql.Connection;
            
            public class TestConfiguration {
            
              @Test
              public void testOverrideConfig() throws Exception {
                JavaConfigApplicationContext context = new JavaConfigApplicationContext(DataSourceConfiguration.class);
                //override default configuration
                DefaultConfig customConfig = context.getBean(DefaultConfig.class);
                customConfig.setDriverClass("com.mysql.jdbc.Driver");
                customConfig.setJdbcUrl("jdbc:mysql://localhost/test");
                customConfig.setUser("root");
                customConfig.setPassword("mysql");
                DataSource dataSource = context.getBean(DataSource.class);
                Connection connection = dataSource.getConnection();
                assertEquals("MySQL", connection.getMetaData().getDatabaseProductName());
              }
            
              @Configuration
              static class DataSourceConfiguration {
                //default driver configuration    
                private String driverClass = "org.hsqldb.jdbcDriver";
                private String jdbcUrl = "jdbc:hsqldb:mem:test";
                private String user = "sa";
                private String password = "";
            
                @Bean
                public DefaultConfig defaultConfig() {
                  DefaultConfig defaultConfig = new DefaultConfig(driverClass, jdbcUrl, user, password);
                  return defaultConfig;
                }
            
                @Bean
                public DataSource dataSource() {
                  DriverManagerDataSource dataSource = new DriverManagerDataSource();
                  DefaultConfig config = defaultConfig();
            
                  dataSource.setDriverClassName(config.getDriverClass());
                  dataSource.setUrl(config.getJdbcUrl());
                  dataSource.setUsername(config.getUser());
                  dataSource.setPassword(config.getPassword());
                  return dataSource;
                }
            
              }
            
              static class DefaultConfig {
                private String driverClass;
                private String jdbcUrl;
                private String user;
                private String password;
            
                DefaultConfig(String driverClass, String jdbcUrl, String user, String password) {
                  this.driverClass = driverClass;
                  this.jdbcUrl = jdbcUrl;
                  this.user = user;
                  this.password = password;
                }
            
                public String getDriverClass() {
                  return driverClass;
                }
            
                public void setDriverClass(String driverClass) {
                  this.driverClass = driverClass;
                }
            
                public String getJdbcUrl() {
                  return jdbcUrl;
                }
            
                public void setJdbcUrl(String jdbcUrl) {
                  this.jdbcUrl = jdbcUrl;
                }
            
                public String getUser() {
                  return user;
                }
            
                public void setUser(String user) {
                  this.user = user;
                }
            
                public String getPassword() {
                  return password;
                }
            
                public void setPassword(String password) {
                  this.password = password;
                }
            
              }
            }
            Thanks!
            Arul
            Last edited by aruld; Oct 14th, 2008, 01:44 PM. Reason: updated sub-title

            Comment


            • #7
              The DataSource bean (like all beans) is eagerly instantiated during the construction of JavaConfigApplicationContext. So, by the time you reset the values in DefaultConfig, it's too late.

              You have at least a couple of options.

              1) make the DataSource bean @Bean(lazy=Lazy.TRUE).
              2) make the DataSource bean @Bean(scope=DefaultScopes.PROTOTYPE)

              The second option isn't likely to be viable though - if you have multiple objects depending on DataSource, you'll want them all talking to the same instance, I'm sure.

              - C

              Comment


              • #8
                Thanks Chris.

                It worked like a charm as always with SJC

                -Arul

                Comment


                • #9
                  great news!

                  Comment


                  • #10
                    Adding JpaConfiguration to context fails to override default DataSourceConfiguration

                    Hi Chris,

                    This works only if I include DataSourceConfiguration to the JavaConfigApplicationContext. If I include both DataSourceConfiguration and JpaConfiguration, the override does not work. It always falls back to the default datasource.

                    Here is my configuration classes for your reference.

                    JpaConfiguration

                    Code:
                    @Configuration
                    @AnnotationDrivenTx
                    @AnnotationDrivenConfig
                    @Import({DataSourceConfiguration.class})
                    public abstract class JpaConfiguration extends ConfigurationSupport {
                    
                      @ExternalBean
                      abstract DataSource dataSource();
                    
                      @Bean
                      public JpaVendorAdapter jpaVendorAdapter() {
                        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
                        adapter.setShowSql(true);
                        adapter.setGenerateDdl(false);
                        adapter.setDatabasePlatform("org.hibernate.dialect.MySQLInnoDBDialect");
                        return adapter;
                      }
                    
                      @Bean(lazy = Lazy.TRUE)
                      public EntityManagerFactory entityManagerFactory() {
                        Properties jpaProperties = new Properties();
                        jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
                        jpaProperties.put("hibernate.show_sql", true);
                    
                        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
                        em.setPersistenceUnitName("myPU");
                        em.setJpaDialect(jpaDialect());
                        em.setJpaProperties(jpaProperties);
                        em.setDataSource(dataSource());
                        em.setJpaVendorAdapter(jpaVendorAdapter());
                        em.setLoadTimeWeaver(loadTimeWeaver());
                        return this.getObject(em, EntityManagerFactory.class);
                      }
                    
                      @Bean
                      public JpaDialect jpaDialect() {
                        return new HibernateJpaDialect();
                      }
                    
                      @Bean
                      public InstrumentationLoadTimeWeaver loadTimeWeaver() {
                        return new InstrumentationLoadTimeWeaver();
                      }
                    
                      @Bean(lazy = Lazy.TRUE)
                      public PlatformTransactionManager transactionManager() {
                        JpaTransactionManager txManager = new JpaTransactionManager();
                        txManager.setEntityManagerFactory(entityManagerFactory());
                        txManager.setJpaDialect(jpaDialect());
                        txManager.setDataSource(dataSource());
                        return txManager;
                      }
                    }
                    DataSourceConfiguration
                    Code:
                    @Configuration
                    public abstract class DataSourceConfiguration extends ConfigurationSupport {
                      @Bean(lazy = Lazy.TRUE)
                      public DataSource dataSource() {
                        DriverManagerDataSource dataSource = new DriverManagerDataSource();
                        CustomConfiguration config = customConfiguration();
                        dataSource.setDriverClassName(config.getDriverClass());
                        dataSource.setUrl(config.getJdbcUrl());
                        dataSource.setUsername(config.getJdbcUsername());
                        dataSource.setPassword(config.getJdbcPassword());
                        return dataSource;
                    
                      }
                    
                      @Bean
                      public CustomConfiguration customConfiguration() {
                        String driverClass = "org.h2.Driver";
                        String jdbcUrl = "jdbc:h2:mem:test";
                        String user = "sa";
                        String password = "";
                    
                        CustomConfiguration config = new CustomConfiguration();
                        config.setDriverClass(driverClass);
                        config.setJdbcUrl(jdbcUrl);
                        config.setJdbcUsername(user);
                        config.setJdbcPassword(password);
                        return config;
                      }
                    }
                    CustomConfiguration

                    Code:
                    public class CustomConfiguration {
                      private String driverClass;
                      private String jdbcUrl;
                      private String jdbcUsername;
                      private String jdbcPassword;
                      //getters/setters omitted
                    }
                    Test
                    Code:
                      @Test
                      public void testOverrideConfig() throws Exception {
                        JavaConfigApplicationContext context = new JavaConfigApplicationContext(DataSourceConfiguration.class, JpaConfiguration.class);
                        //override default configuration
                        CustomConfiguration customConfig = context.getBean(CustomConfiguration.class);
                        customConfig.setDriverClass("com.mysql.jdbc.Driver");
                        customConfig.setJdbcUrl("jdbc:mysql://localhost/test");
                        customConfig.setJdbcUsername("root");
                        customConfig.setJdbcPassword("secret");
                        DataSource dataSource = context.getBean(DataSource.class);
                        Connection connection = dataSource.getConnection();
                        assertEquals("MySQL", connection.getMetaData().getDatabaseProductName());
                    
                      }
                    Please clarify this issue.

                    Thanks!
                    Arul

                    Comment


                    • #11
                      I posted too quickly

                      If I try your other suggestion by making the DataSource bean @Bean(scope=DefaultScopes.PROTOTYPE), this works.

                      Do you think this approach guarantees this to work in all cases?

                      -Arul

                      Comment


                      • #12
                        When I try to query JPA entities with this approach, I get the below error.

                        Code:
                        Exception in thread "main" org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
                        	at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:375)
                        	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:377)
                        	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:263)
                        	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101)
                        	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                        	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
                        	at $Proxy46.exists(Unknown Source)
                        	at impl.DaoImpl.<init>(DaoImpl.java:145)
                        	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:585)
                        	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
                        Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
                        	at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
                        	at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:41)
                        	at org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:70)
                        	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:52)
                        	at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:330)
                        	... 17 more
                        Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
                        	at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
                        	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
                        	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
                        	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
                        	at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
                        	at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
                        	at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
                        	at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
                        	at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1353)
                        	at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:38)
                        	... 20 more
                        Caused by: java.sql.SQLException: Connections could not be acquired from the underlying database!
                        	at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
                        	at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:529)
                        	at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
                        	at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:46)
                        	at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
                        	... 25 more
                        Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
                        	at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1319)
                        	at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
                        	at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
                        	at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
                        	... 28 more
                        Do you have any clues as to why this is happening?

                        Thanks!
                        Arul

                        Comment

                        Working...
                        X