How to programmatically tell `Spring Boot` to load configuration files from `custom location` when doing JUNIT Test - spring-boot

How to programmatically tell Spring Boot to load configuration yaml files from custom location when doing JUNIT Test.
In program, I could use properties of SpringApplicationBuilder to specify my custom yaml file .
#Configuration
#SpringBootApplication
#ComponentScan
public class SampleWebApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(SampleWebApplication.class)
.properties("spring.config.name:application,conf",
"spring.config.location=classpath:/viaenvironment.yaml")
.build().run(args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("app.name"));
}
}
When doing JUNIT Test, how should I configure it?
I'm using spring boot 1.5.1.

Please use this option to set the spring.config.location through #TestPropertySource:
#TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" }

Related

How to convert plain java main method program on docker

I wanted to migrate/run old java code to docker using Jenkins.
It is structured to run using normal main method of java (Jar file having main method is executed through some script).
Its making use of spring.xml(applicationContext.xml) files with spring-context-2.5.xsd
Uses properties file for all configurations.
Questions as I am looking for recommendations now on:
Does this project needs to be migrated to spring-boot application for migrating to/creating docker image?
If yes, please have a look at current code block
Do I need to replace properties files by yml files?
Current code of main class can be framed as :
public class SIIRunner {
public static void main(String[] args){
String envStr = null;
if (args != null && args.length > 0) {
envStr = args[0];
}
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
SIIExecutor siiExecutor= (SIIExecutor) ctx.getBean("SIIExecutor");
siiExecutor.pollAndOperate();
}
}
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
ApplicationContext app = SpringApplication.run(Application.class,
args);//init the context
SIIExecutor siiExecutor = (SIIExecutor)
app.getBean(SIIExecutor.class);//get the bean by type
}
#Bean // this method is the equivalent of the <bean/> tag in xml
public SIIExecutor getBean(){
return new SIIExecutor();
}
}
As long as you are starting with a base #Configuration class to begin with, which it maybe sounds like you are with #SpringBootApplication, you can use the #ImportResource annotation to include an XML configuration file as well.
#SpringBootApplication
#ImportResource("classpath:beanFileName.xml")
public class SpringConfiguration {
//
}
Spring boot ideal concept is avoid xml file. but if you want to keep xml bean, you can just add #ImportResource("classPath:beanFileName.xml")
I would recommend remove the beanFileName.xml file. and, convert this file to spring annotation based bean. So, whatever class has been created as bean. Just write #Service or #Component annotation before class name. for example:
XML based:
<bean ID="id name" class="com.example.MyBean">
Annotation based:
#Service or #Component
class MyBean {
}
And, add #ComponentScan("Give the package name").
This is the best approach. Hope this helps.

How to load all .yml files from resources directory at the time of application startup in spring?

I have 2-3 .yml files in resources directory in a spring application.
I want to load all these files at the application startup automatically.
I tried below code but did not work.
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(YamlLoadApplication.class)
.properties("spring.config.name:applicationTest,CountriesData",
"spring.config.location:src/main/resources/")
.build().run(args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
MutablePropertySources sources = environment.getPropertySources();
Please help me to solve this. What is the best way to achive this? I would be using all these yml files values throughout the application.
Thanks
You can use #PropertySource annotation to externalize your configuration to a properties file.
Spring recommends using Environment to get the property values.
env.getProperty("mongodb.db");
You can mention the property files which are using in the class.
#Configuration
#PropertySource({
"classpath:config.properties",
"classpath:db.properties"
})
public class AppConfig {
#Autowired
Environment env;
}
From Spring 4 you can ignoreResourceNotFound to ignore the not found properties file
#PropertySources({
#PropertySource(value = "classpath:missing.properties", ignoreResourceNotFound=true),
#PropertySource("classpath:config.properties")
Examples are from the article - https://www.mkyong.com/spring/spring-propertysources-example/
Refer the article if you need more information
From Spring documentation
One issue here "spring.config.location:src/main/resources/" sets spring.config.location to src/main/resources/ which is not a class path resource but a file system resource. This is looked up from the current directory you're running your Spring Boot application from.
Several fixes:
Specify a full file system path like this:
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext;
applicationContext = new SpringApplicationBuilder(YmlsApplication.class)
.properties("spring.config.name:applicationTest,CountriesData",
"spring.config.location:/Users/msimons/tmp/configs/")
.build().run(args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
MutablePropertySources sources = environment.getPropertySources();
sources.forEach(p -> System.out.println(p.getName()));
}
Or specify a classpath resource. Notice that I put the config files under a separate directory, which lives in src/main/resources/custom-config:
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext;
applicationContext = new SpringApplicationBuilder(YmlsApplication.class)
.properties("spring.config.name:applicationTest,CountriesData",
"spring.config.location:classpath:/custom-config/")
.build().run(args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
MutablePropertySources sources = environment.getPropertySources();
sources.forEach(p -> System.out.println(p.getName()));
}
Notice classpath: inside the path and also starting the directory at the root level of resources with /.

Replace Beans.xml configuration in Spring

How can I replace beans.xml file for testing purposes?
I use
#SpringBootApplication
#ImportResource("classpath:Beans.xml")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
to init class, but in my testing class
#RunWith(SpringRunner.class)
#SpringBootTest
public class ArrayCointainerTest {
I'd like to use another one.
Any idea for this?
Define a separate configuration class which has you beans xml imported and annotate that with #TestConfiguration. Spring boot automatically pick this up as your test configuration
Detecting test configuration

Spring Boot : PropertySourcesPlaceholderConfigurer is not loading system properties

I have a Spring Boot application as follows:
#SpringBootApplication
#PropertySource(ignoreResourceNotFound=true,value={"classpath:application.properties","classpath:util-${spring.profiles.active}.properties"})
#ComponentScan("com.jmarts")
#EnableTransactionManagement
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilderconfigure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
I'm making use of spring profiles and based on active profile, a the correct environment specific file is loaded: utils-local.properties, utils-dev.properties, etc...
When profile is set through application.properties (spring), e.g. spring.profiles.active=local all works great, correct file (utils-local.properties)is loaded.
Providing profile through -D (gradle bootRun -Dspring.profiles.active=local) doesn't load profile. I was able to verify that the system properties is passed (print systemProperties)
I assume spring boot will register a PropertySourcesPlaceholderConfigurer if none is configured.
spring boot officially supports profile-specific properties using the naming convention application-{profile}.properties.
so you can remove "classpath:util-${spring.profiles.active}.properties" and add application-local.properties, application-dev.properties and so on in the classpath.

How to externalize application.properties to an external filesystem location in Spring Boot?

#ComponentScan
#EnableAutoConfiguration
#PropertySource(value = { "file:/Users/Documents/workspace/application.properties" })
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
}
In this case it gives while deploying:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency:
Not able to find the correct way to externalize the application properties file
I tried autowiring environment variable which is correctly loaded but then I need to manually define all the beans
#Bean
public JdbcTemplate dataSource() {
String driverClassName = env
.getProperty("spring.datasource.driverClassName");
String dsUrl = env.getProperty("spring.datasource.url");
String username = env.getProperty("spring.datasource.username");
String password = env.getProperty("spring.datasource.password");
//DataSource dataSource = new SimpleDriverDataSource(new driverClassName, dsUrl, username, password);
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
return jdbc;
}
This deploys without throwing error but not responding.
If you're deploying a WAR to Tomcat, then you need to define a context XML as described here: https://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Defining_a_context
For example, you would typically define $CATALINA_BASE/conf/Catalina/localhost/my-app.xml if you have http://localhost:8080/my-app/.
The file would then look like this:
<Context docBase='path/to/my-app/my-app.war'>
<Environment name='app_config_dir' value='path/to/my-app/' type='java.lang.String'/>
</Context>
In your code, implement ApplicationContextAware and override setApplicationContext. Here is an example:
public class Setup implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("Set application context. App Config Property: {}",applicationContext.getEnvironment().getProperty("app_config_dir"));
}
}
You can now load the properties file from app_config_dir.
There is no need to define it by using #PropertySource annotation. You should just use spring.config.location property to set your application.properties location. That property can be set up for example in command line:
java -jar myapp.jar --spring.config.location=/Users/Documents/workspace/
You can define an environment variable called SPRING_CONFIG_LOCATION and give it a value that can be a folder (which should end in /) or a file. In any case the location should pe prefixed with file::
SPRING_CONFIG_LOCATION = file:C:/workspace/application.properties
or
SPRING_CONFIG_LOCATION = file:C:/workspace/
More about this here.
You can use #PropertySource too because it is useful when you are deploying application as war file to tomcat.
#PropertySource is not working because you are missing #Configuration annotation. As per the Spring-Boot documentation, #PropertySource annotations should be present on your #Configuration classes.
Following works
#Configuration
#ComponentScan
#EnableAutoConfiguration
#PropertySource(value = { "file:/Users/Documents/workspace/application.properties" })
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
}
You can also load multiple properties file. For ex:
#PropertySource(value = {"classpath:application.properties", "file:/Users/overriding.propertis"}, ignoreResourceNotFound = true)
Note that the order of the declared files is important. If the same key is defined in two or more files, the value associated with the key in the last declared file will override any previous value(s).

Resources