#Profile cause Unable to start EmbeddedWebApplicationContext - spring

im trying to use #Profile functionality to separate production/dev environment configuration and 'tests' config. But when I add #Profile to my configuration class I get:
Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:124)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:476)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at mypackage.configuration.PhoenixConfiguration.main(PhoenixConfiguration.java:26)
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:174)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:147)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:121)
... 7 more
Configuration class looks like this:
#Configuration
#EnableAutoConfiguration
#ComponentScan("mypackage")
#EnableJpaRepositories(basePackages = "mypackage.repository")
#EntityScan(basePackages = "mypackage.phoenix.domain")
#PropertySource("classpath:properties/application-production.properties")
#EnableWebMvc
#Profile("production")
public class PhoenixConfiguration extends WebMvcConfigurerAdapter{
public static void main(String[] args) throws Exception {
SpringApplication.run(PhoenixConfiguration.class, args);
}
}
ive tried to set active profile to production in application-production.properties
spring.profiles.active=production (with and without " )
or cmd command: mvn spring-boot:run -Dspring.profiles.active=production
nothing helps. Ofcourse everything works when I remove #Profile, but then I my tests are using production database ; )

If you add the profile your whole application basically stops working because your main entry point is annotated with #Profile.
I suggest you let Spring Boot do its work at the moment it appears as if you are trying to work very hard around Spring Boot and you are making things, imho, too complex.
Spring Boot will autodetect Spring Data JPA and the fact that you have Spring Web on your classpath. So remove #EnableJpaRepositories and #EnableWebMvc and don't let your class extends WebMvcConfigurerAdapter.
Spring boot by default will load the application.properties for you instead of putting in in properties either place it in the root of your classpath or config. At least remove the #PropertySource as Spring Boot will just load it. If you want to keep the properties path add the spring.config.location property which then points to your properties directory.
Finally I would probably also rename the file to PhoenixApplication but that is just me. That should leave you with something like
#Configuration
#EnableAutoConfiguration
#ComponentScan("mypackage")
#EntityScan(basePackages = "mypackage.phoenix.domain")
public class PhoenixApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(PhoenixApplication.class, args);
}
}
Now simply put your production configuration in the application.properties and put another one in src/test/resources to contain your test configuration. At runtime only the first will be available when testing the latter will override properties from the first.
If you really want to use profiles I would suggest doing it the other way around, configure for production and override for test. Then simply add #ActiveProfiles to your test case.
#ActiveProfiles("test")
#SpringApplicationConfiguration(classes=PhoenixApplication.class)
public class YourTest {}
This will start a test which will load the default application.properties and a application-test.properties which you can simply place in src/test/resources.

Related

How to make spring boot test app independent of external property source?

I am writing a controller test for a spring boot application. To use the spring application context I am using SpringRunner class. The problem is the main application class has a property source defined to a specific file path.
When I am running the test I am getting a FileNotFound exception from the hardcoded file. I want my test to be independent of this property source.
I cannot add the 'ignoreResourceNotFound' option for property source in the main application.
Below is the main application class with property source defined.
#SpringBootApplication
#PropertySource("file:/opt/system/conf/smto/management.properties")
#EnableConfigurationProperties
public class ManagementApp {
public static void main(String[] args) {
SpringApplication.run(ManagementApp.class, args);
}
}
I am also adding my test class below
#RunWith(SpringRunner.class)
#TestPropertySource(locations = {"classpath:application.properties","classpath:management.properties"})
#DirtiesContext
#EmbeddedKafka(topics = {"management-dev"},partitions = 1,
controlledShutdown = false,brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"})
#AutoConfigureMockMvc
#WebMvcTest(Controller.class)
public class ControllerTest {
}
I have found a workaround to create the spring context in this scenario. I have changed my testing class package and because of it, the spring-boot test cannot find the primary configuration class. And then provided all the required packages to create the application context.
Reference for this solution found from spring docs here.
Spring Boot’s #*Test annotations will search for your primary configuration automatically whenever you don’t explicitly define one.
The search algorithm works up from the package that contains the test until it finds a #SpringBootApplication or #SpringBootConfiguration annotated class. As long as you’ve structured your code in a sensible way your main configuration is usually found.

Is ApplicationContext automatically instantiated in Spring?

Is ApplicationContext automatically instantiated in Spring?
If I have my bean defined like this
#Component
public class Car{
...
}
and then I have my config class which tells Spring container where to look for beans through the annotation #ComponentScan
#Configuration
#ComponentScan
public class AppConfig {
...
}
Is Spring automatically creating a context loading all my beans? Or do I have to create it programmatically? If so how do I do it, with something like this?
#Configuration
#ComponentScan
public class AppConfig {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean(Car.class);
...
}
Even doing this, there may be a problem, because every time I need the context I have to call new AnnotationConfigApplicationContext...
what is the recommended way to instantiate the context and making him available inside the whole project, maybe as a bean like inside Spring boot app where i can just autowire it.
How Spring Boot can initialize it, load all the beans and let the context available as a bean, ready to be autowired?
No, Application Context isn't automatically instantiated, if you're having a simple and basic Spring Core application. Moreover, your #Configuration class won't scan anything and won't create any beans, if you don't create your Spring Container/Context explicitly with that #Configuration class.
There are several ways of creating Application Context, but the most popular and traditional ones are:
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml) - implying, that you have your container configuration in the applicationContext.xml file;
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigClass.class); - implying, that your ConfigClass is the #Configuration class.
However, if you have the Spring Boot application annotated with #SpringBootApplication, then the Application Context will be automatically instantiated for you, because:
#SpringBootApplication annotation consists of:
#EnableAutoConfiguration - which enables Spring Boot’s auto-configuration mechanism;
#ComponentScan - which enable #Component scan on the package where the application is located;
#Configuration - allows to register extra beans in the context or import additional configuration classes.
and this will spin up the context for you.
You can obtain the reference to the Spring Context created by Spring Boot, by the factory method you have in your main method: SpringApplication.run(MainClass.class, args);
This returns the reference to the Application Context and you can assign it to variable like this:
ApplicationContext context = SpringApplication.run(MainClass.class, args)

Data JPA Test with reactive spring

I want to test the repository layer and I'm using spring webflux. My test class is as follows
#RunWith(SpringRunner.class)
#DataJpaTest
public class DataTester {
#Autowired
private MyRepository repository;
#Test
.....
}
Even though this would work in spring-mvc when using spring-weblux I get the following error.
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.context.ApplicationContextException: Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean.
How to resolve this? If I am to start the whole application context with #SpringBootApplication it works. Any other options without using that?
The reason for this was that in the application.properties the application type was set as reactive.
spring.main.web-application-type=reactive
This tries to auto configure a web server in this case a reactive web server. As #DataJpaTest does not provide a bean for that, this fails. This can be fixed in either two ways.
One is by Adding an application.properties file in the resources directory of the test package and setting the value as,sprig.main-web-application-type=none solves this issue.
Or we can simple pass a property value to the annotation as follows. #DataJpaTest(properties = "spring.main.web-application-type=none")
If you are using Spring Boot 2+ then only #DataJpaTest is enough on test class.
So your test class should be
#DataJpaTest
public class DataTester {
#Autowired
private MyRepository repository;
#Test
.....
}

Convert a Spring MVC application to Spring Boot - BeanCurrentlyInCreationException issue

I have a Spring MVC application, using Hibernate for my entities persistence management. I am able to build, deploy and run it on some application server such as glashfish or tomcat, all is fine.
Now, I want to convert it into a Spring Boot application. I added the following class:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(Application.class, args);
}
}
and added the spring-boot, spring-boot-autoconfigure, and spring-boot-starter-tomcat dependencies to my pom.
Alas, when trying to run the application, I get the following error:
BeanCurrentlyInCreationException: Error creating bean with name
'MyClassDAO': Bean with name 'MyClassDAO' has been injected into
other beans [MyOtherClassDAO] in its raw version as part of a circular
reference, but has eventually been wrapped. This means that said other
beans do not use the final version of the bean. This is often the result
of over-eager type matching - consider using 'getBeanNamesOfType' with
the 'allowEagerInit' flag turned off, for example.
I don't know how to use 'getBeanNamesOfType' and set the allowEagerInit off (I do not use XML configuration). Of course, I'm not sure this would solve my issue anyway.
Any ideas on how I can fix this?
If it's really some intilization issue then i believe the you must be having your class in other package and due to some cache issues it doesn't include those classes in class path to scan in container so to do this manually you can put a annotation just below #springbootapllication is #EnableComponentScan("enter the package name of the class which is not initializing") also on that dao class put #service or #component annotation to let the application include then in container

Spring Boot - Autowiring a DataSource Bean

I have a basic Spring Boot application annotated like this:
#SpringBootApplication
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
I have the following entries in my application.properties file:
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/db
spring.datasource.username=dbuser
spring.datasource.password=dbpassword
From my understanding Spring Boot should be able to automatically autowire a DataSource Bean from these properties.
However if I try:
#Autowired
DataSource dataSource;
anywhere in my application (f.i. in #Configuration files), I get the following error in IntelliJ:
"Could not autowire. No beans of 'DataSource' type found."
Is there something obvious that I'm missing for this to work?
I have a single DataSource.
The bean actually does get initialized correctly. This is possibly just an IntelliJ tooltip bug.
Adding #SuppressWarnings to hide the message will work without further issues.
Intelij apparently even in the 2016.2 still does not support the #SpringBootApplication annotation. You either have to remove the #SpringBootApplication annotation and replace it with the #Configuration, #EnableAutoConfiguration and #ComponentScan annotations or just ignore the errors.

Resources