Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one programmatically create a Spring context?

Does anyone know if there any way that I can programmatically create a bean context?

I want to be able to do something like:

ConfigurableApplicationContext c = new ConfigurableApplicationContext();
BeanDefinition bd = new BeanDefinition();
bd.setId("id");
bd.setClassName("classname");
bd.setProperty("propertyName", propertyValue");
...etc...

or better still be able to inject a ready made bean into the application context:

c.addBean("beanId", beanObject);

Or if I'm using annotations:

c.setAnnotationAware(true);
c.setAnnotationScanBasePackage("packagename");

or

c.addAnnotatedSpringClass("classnamethatisannotated");

The rationale for this is that I want to be able override bean definitions for the purpose of testing - In my test I create this new application context, configured with code in the test (not in xml) and then make this test application context have as a parent the SUT application context.

I haven't found any code in the spring libraries that can do this. Has anyone built something like this? Would it be possible to build something like this? I know the former approach is doable, I'm not 100% sure the latter approaches will work without conditions.

like image 299
Michael Wiles Avatar asked Jun 10 '09 09:06

Michael Wiles


2 Answers

Try either:

  • Spring JavaConfig
  • Grails BeanBuilder
  • new AtUnit

JavaConfig code sample

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

BeanBuilder code sample

def bb = new grails.spring.BeanBuilder()

bb.beans { 
  dataSource(BasicDataSource) { 
    driverClassName = "org.hsqldb.jdbcDriver" 
    url = "jdbc:hsqldb:mem:grailsDB" 
    username = "sa" 
    password = "" 
  } 

  sessionFactory(ConfigurableLocalSessionFactoryBean) { 
    dataSource = dataSource
    hibernateProperties = [ "hibernate.hbm2ddl.auto":"create-drop", "hibernate.show_sql":true ] 
  }   
}

AtUnit code sample

Unit test

@RunWith(AtUnit.class)
@Container(Container.Option.SPRING)
@MockFramework(MockFramework.Option.EASYMOCK)
public class ExampleSpringEasyMockTest {

    @Bean @Unit UserManagerImpl manager;
    @Bean("fred") User fred;
    @Bean("userDao") @Mock UserDao dao;
    @Bean("log") @Stub Logger log;

    @Test
    public void testGetUser() {
        expect(dao.load(1)).andReturn(fred);
        replay(dao);
        assertSame(fred, manager.getUser(1));
        verify(dao);
    }


}

Context file ( private for the test )

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

  <bean id="userManager" class="atunit.example.subjects.UserManagerImpl">
      <constructor-arg ref="log"/>
      <property name="userDao" ref="userDao"/>
  </bean>

  <bean id="fred" class="atunit.example.subjects.User">
      <property name="id" value="500"/>
      <property name="username" value="fred"/>
  </bean>

</beans>
like image 69
Robert Munteanu Avatar answered Oct 17 '22 14:10

Robert Munteanu


Why don't you just use two different contexts? one for production, one for tests... you're going about this the hard way.

like image 28
Chochos Avatar answered Oct 17 '22 13:10

Chochos