I really don't now if is this user case apply, but I saw a lot of people with the some problem: how to set a active profile without messing with bash variables or java system.properties?
The most common case: you have a "jndi" connection to your database in your production code, but the integration tests runs with a local driver.
Until now (Spring 3.1) you have a lot of xml files and with some profiles in Maven (don't confuse them with Spring profiles) you copy the desired one to the default if you are in production, or in dev, etc.
When I read about profiles in Spring I thought that mess is over. A simple property file with my active profile et voilá. Well not so fast.
A sample test file with context in @Configuration classes
Code:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {MongoTemplateConfig.class, LazVirtualMongoConfig.class, ProductionMongoConfig.class})
public class MongoTest {
@Autowired
private MongoTemplate mongoTemplate;
@Test
public void crudTest() {
mongoTemplate.dropCollection(PersonTrack.class);
...
The configuration classes
Ex:
Code:
@Configuration
@Profile("dev")
public class LazVirtualMongoConfig implements MongoConfig {
@Override
public @Bean
MongoFactoryBean mongo() {
MongoFactoryBean mongo = new MongoFactoryBean();
mongo.setHost("lazvirtual.iol.pt");
mongo.setWriteConcern(WriteConcern.SAFE);
return mongo;
}
}
are annotated with different profiles and everything works fine if I put the @ActiveProfile("dev") or @ActiveProfile("prd") in the test class.
But that gives me again a hard coded configuration!
What I need is the possibility of reading a external property file and set my active profile before the AnnotationConfigContextLoader registries the configuration classes.
After reading everything Google gives me about the subject I find the solution in... the javadoc of AbstractGenericContextLoader:
Code:
/**
* Prepare the {@link GenericApplicationContext} created by this<code>ContextLoader</code>.
* Called <i>before</i> bean definitions are read.
* <p>The default implementation is empty. Can be overridden in subclasses to
* customize <code>GenericApplicationContext</code>'s standard settings.
* @param context the context that should be prepared
* @see #loadContext(MergedContextConfiguration)
* @see #loadContext(String...)
* @see GenericApplicationContext#setAllowBeanDefinitionOverriding
* @see GenericApplicationContext#setResourceLoader
* @see GenericApplicationContext#setId
* @since 2.5
*/
protected void prepareContext(GenericApplicationContext context) {
}
The AnnotationConfigContextLoader extends this class and mine become:
Code:
public class MyAnnotationConfigContextLoader extends AnnotationConfigContextLoader{
@Override
protected void prepareContext(GenericApplicationContext context){
try {
context.getEnvironment().getPropertySources().addFirst(new ResourcePropertySource("classpath:env.properties"));
} catch (IOException ex) {
}
context.getEnvironment().setActiveProfiles(context.getEnvironment().getProperty("env"));
}
}
And it works like a champion.
The only thing we have to do is change the annotation to
Code:
@ContextConfiguration(loader = MyAnnotationConfigContextLoader.class, classes = {MongoTemplateConfig.class, LazVirtualMongoConfig.class, ProductionMongoConfig.class})
If someone has a better aproach....