0

I am using Spring 4.3.0.I am writing a SDK in that i am having the following classes,

Providers.java

@ComponentScan
@Service
//@PropertySource("classpath:application.properties")
public class Providers {

@Autowired
ApplicationContext context;

public Providers(){
}

public Providers(ApplicationContext applicationContext){
    this.context = applicationContext;
}

//...Other SDK component code
}

ProvidersBuilder.java

public class ProvidersBuilder {
//Set providers property
public Providers build() throws LifecycleException, InsufficientPropertiesException {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext();

    StandardEnvironment env = new StandardEnvironment();
    context.setEnvironment(env);
    if(cond1){
        context.getEnvironment().addActiveProfile("profile1");
    }
    if(cond2){
        context.getEnvironment().addActiveProfile("profile2");
    }
    ...etc
    context.setParent(null);
    context.register(Providers.class);
    context.refresh();
    Providers Providers = new Providers(context);

    return Providers;
}
}

I have following configuration for Spring-Junit test classes,

SpringContextLoader.java

@ComponentScan(basePackages = "com.providers.global")
@PropertySource("classpath:application.properties")
public class SpringContextLoader {

public static void main(String[] args) throws Exception {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(SpringContextLoader.class);
}
}

In one of my test class, I am trying to print all the profiles,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringContextLoader.class)
public class ProvidersTest{

@Autowired
ApplicationContext context;

@Before
public void beforeMethod() throws Exception {
    String[] profiles = context.getEnvironment().getActiveProfiles();
    if(profiles != null && profiles.length > 0){
        for (String string : profiles) {
            logger.info(String.format("Active Profiles in test::%s",string));
        }
    }

}

@Test
public void activateProviders() throws Exception{
...invoking test call
}
}

In the logs i am able to see only the profiles configured in application.properties, but i would like to get the profiles which are dynamically added in ProvidersBuilder.java.

Basically i would run ProvidersTest only for particular profiles for that i am using the following annotation, @IfProfileValue(name = "spring.profiles.active", values = { "charging" }) Since application context always returns default profile configured in application.properties this class never get a chance to run.

Could anyone please help me to resolve this issue.Why the profiles added in ProvidersBuilder.java is not available in ProvidersTest.java?

**Edit 1 **

SpringContextLoader.java

@ComponentScan(basePackages = "com.providers.global")
@PropertySource("classpath:application.properties")
public class SpringContextLoader {

@Bean(name = "ConfigApplicationContext")
public AnnotationConfigApplicationContext applicationContext() {
     AnnotationConfigApplicationContext context =
             new AnnotationConfigApplicationContext();
     return context;
}
}

Now we are not creating new AnnotationConfigApplicationContext anywhere in application.

ProvidersBuilder.java

public class ProvidersBuilder {

@Autowired
@Qualifier("ConfigApplicationContext")
public AnnotationConfigApplicationContext context;

//Set providers property
public Providers build() throws LifecycleException, InsufficientPropertiesException {

context.setEnvironment(env); **Here i am getting getting NullPointerException**
if(cond1){
    context.getEnvironment().addActiveProfile("profile1");
}
if(cond2){
    context.getEnvironment().addActiveProfile("profile2");
}
...etc
context.setParent(null);
context.register(Providers.class);
context.refresh();
Providers Providers = new Providers(context);

return Providers;
}
}

In the ProvidersBuilder.java while getting "AnnotationConfigApplicationContext context" using @Autowired it returns null.

Roman
  • 6,486
  • 2
  • 23
  • 41
VelNaga
  • 3,593
  • 6
  • 48
  • 82
  • 1
    Your setup is flawed, in multiple ways. Your `SpringContextLoader` should be a `@Configuration` class, the `main` in that class doesn't really do a thing, and why are you recreating the same context again in your `ProvidersBuilder.build` method, that latter which I hope is really being called only once. Your test completly ignores the `ProviderBuilder` becuase you aren't using it anywhere. – M. Deinum Aug 02 '16 at 18:43
  • @M.Deinum Thank you for your reply. could you please guide me to resolve the issue. What are all the changes I should do?is there any best practices we should follow? – VelNaga Aug 02 '16 at 21:30
  • I don't think i need a SpringContextHolder so we can remove that but how can i call "AnnotationConfigApplicationContext" created in ProviderBuilder in my test classes? – VelNaga Aug 03 '16 at 12:49
  • @M.Deinum I edited my question as per your suggestion i did few changes but getting nullPointerException while getting "AnnotationConfigApplicationContext" bean.Kindly guide me to resolve this issue – VelNaga Aug 03 '16 at 16:17
  • I have a hard time grasping what you are trying to achieve, at one hand you are trying very hard to use Spring and the next moment (in the same class) you are completly bypassing Spring. (Your `build` method is a good example of that). – M. Deinum Aug 04 '16 at 08:44
  • @M.Deinum again it's very hard to understand your point.Now i made the SpringcontextLoader as common and instead of creating new "AnnotationConfigApplicationContext" in ProviderBuilder i am betting the bean from SpringContextHolder But no luck getting nullPointerException – VelNaga Aug 04 '16 at 08:46
  • I am unsure whether this is a proper way.But goal is simple based on some user defined properties we will create a profile those profiles should be available in my test class. So that based on the profiles i will invoke the test class – VelNaga Aug 04 '16 at 08:48
  • And without understanding your actual code there is not much to do. It looks like you are trying to use things you don't understand and are trying to work around the framework(s) you are using. – M. Deinum Aug 04 '16 at 08:51
  • Yes i can able to understand it's confusing me while reading the question.Let me explain.I am creating a SDK which will be consumed by lot of microservices. SDK expose services for few components using Providers.java. Not all the microservices consumes all the services in SDK so based on the property passed by microservices we set the profiles and will instantiate those beans in spring container.we used ProviderBuilder.java to set those profiles based on user Defined properties. – VelNaga Aug 04 '16 at 08:58
  • @M.Deinum My test classes should run based on the profiles set inside ProviderBuilder.java – VelNaga Aug 04 '16 at 08:59
  • Your test should reflect how you use yuor API, currently it isn't. Next to that, your code in the `build` method is flawed. You are constructing a context, then discarding it and constructing a `Providers` yourself without using the Spring configured one. Also why are you constructing a context yourself, what is preventing one to call the `build` method multiple times? Which will lead to continuously building the context, eventually leading to memory issues (amongst others). Why aren't the services just using what they need, why do you need a SDK at all? – M. Deinum Aug 04 '16 at 09:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120090/discussion-between-velnaga-and-m-deinum). – VelNaga Aug 04 '16 at 09:03

0 Answers0