I am trying to figure out whether I can load the same .yml property files in testing environment as I load in real.
For example I have a test:
\src\test\java\security\TokenTest.java
Annotated with:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#ActiveProfiles("dev")
Then I have:
\src\main\resources\application.yml
When I run the application, the environment picks up property-source from the yml location.
Whenever I run my test, the environment does not see this file - i.e. property-source is not created/populated.
The obvious solution is to put duplicate file to the test location:
\src\test\resources\application.yml
And it will load, but that is bad - in terms that it raises unnecessary confusion when perceiving the difference between test and main resources.
This previous problem gets enhanced if you have configuration file per environment.
Is there a way to load resources from src/main/resources for tests?
This is probably some basic classpath scanning concept which I don't know.
My case is that I already faced the nightmare when you have 5 yml properties files per enviornment in src/main/resources and then you have 5 corresponding yml properties files in src/test/resources and someone from your team WILL 100 % at some point introduce discrepancy between them making everyone else bleed in the long term.
So by any means tests must refer to the same configuration files not to be the lost within its own void context.
Solution: Try to "rebuild" the project.
Is there a way to load resources from src/main/resources for tests?
It works for me. Maybe your IDE is not copying changes to the output directory on save or something (I have heard IntelliJ users have to switch that feature on)?
I had the same problem as you, but I figured out that it was a classpath problem in my run configuration in intellij, when setting that up like it should have been it worked as a charm loading application.yml from the main/resources.
Related
I explain my problem;
I have a web app developed using Vue.js and Spring Boot, this application working a PDF sheet and saves the file that is generated by Java, I use two lines of code to separate my development part from the production part (I leave you the 2 lines of code like this you understand the concept well)
FileReader leggoFile = new FileReader(System.getProperty("user.dir") + "/temp/webapps/foolder/foolder/file.pdf");
// FileReader leggoFile = new FileReader(System.getProperty("catalina.base") + "/temp/webapps/foolder/foolder/file.pdf");
This whole application is built using the "bootWar gradle plugin" which returns me a .war which I will then upload to a Tomcat server;
My goal is this:
I would like to set a single environment variable so that if I want to build the project I don't have to comment/uncomment that line for example:
FileReader leggoFile = new FileReader({{variableEnvironment}} + "/temp/webapps/foolder/foolder/file.pdf")
my question is this:
How dp Gradle and Spring Boot handle environments? Is there a way to separate environments? Is this possible or should I start thinking differently?
I tried to search on something but unfortunately I was tied to the problem that I don't understand how the .war file is generated through the BootWar Gradle plugin, also searching on the internet I understood that environment Gradle and environment Spring are two separate things but in general even if I know the line of code is wrong in the beginning my question is always the same:
How are environment variables handled in Spring and Gradle?
With Spring Boot, you can add properties to your application by adding an file named application.yaml to your resources folder (src/resources/). In addition you can add properties through application-{profile}.yaml to add properties only for given Spring profiles. For instance application-test.yaml would only be read if "test" is an active profile. When booting up the application, Spring will first read application.yaml, then any profile-specific YAML-files, such that any overlapping properties are replaced.
There are several approaches to injecting the property. A simple solution is to add a field to your component annotated with #Value("${PATH}) and replace PATH with the property's path in the YAML.
Small question regarding a Spring profile (integration) applied to Springboot please.
Currently, under src/main/resources, I have several application.properties files.
Such as:
application properties
application-local.properties
application-production.properties
application-integration.prorperties
And under the src/test/resources, no properties file.
When I run maven, maven will trigger some unit and integration tests. The unit test does not need any particular profile (properties are set in the unit tests, anyway, it is not the question).
The integration tests, they need the application-integration.properties.
And currently, with the file under src/main/resources, everything is fine.
I just tried moving the file to src/test/resources, and the integration tests could not find any property, as if the file disappeared.
What is the proper way to tell Springboot to run integration tests with a application-integration.properties under src/test/resrouces please?
Thank you
You can use the below configuration for the Integration tests
#TestPropertySource(locations = "classpath:application-integration.properties")
#ActiveProfiles("integration")
I have a spring boot application that I can package in a war that I want to deploy to different environments. To automate this deployment it'd be easier to have the configuration file externalized.
Currently everything works fine with a application.properties file in src/main/resources. Then I use ´mvn install´ to build a war deployable to tomcat.
But I would like to use a .yml file that does not need to be present on mvn install but that would be read from during deployment of the war and is in the same or a directory relative to my war.
24. externalized configuration shows where spring boot will look for files and 72.3 Change the location of external properties of an application gives more detail on how to configure this but I just do not understand how to translate this to my code.
My application class looks like this:
package be.ugent.lca;
Updated below
Do I need to add a #PropertySource to this file? How would I refer to a certain relative path?
I feel like it's probably documented in there as most spring boot documentation but I just don't understand how they mean me to do this.
EDIT
Not sure if this should be a separate issue but I think it's still related.
Upon setting the os variable the error of yaml file not found went away. Yet I still get the same error again as when I had no application .properties or .yml file.
Application now looks like this:
#Configuration
**#PropertySource("file:${application_home}/application.yml")**
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
The application_home OS variable
$ echo $application_home
C:\Masterproef\clones\la15-lca-web\rest-service\target
My application.yml file(part it complains about):
sherpa:
package:
base: be.ugent.lca
Error upon java -jar *.war
All variations upon:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'sherpa.package.base' in string value "${sherpa.package.base}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:808)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
... 142 more
Using external properties files
The answer lies in the Spring Boot Docs, I'll try to break it down for you.
First of all, no you should not use #PropertySource when working with Yaml configuration, as mentioned here under the Yaml shortcomings :
YAML files can’t be loaded via the #PropertySource annotation. So in the case that you need to load values that way, you need to use a properties file.
So, how to load propery files? That is explained here Application Property Files
One is loaded for you: application.yml , place it in one of the directories as mentioned in the link above. This is great for your general configuration.
Now for your environment specific configuration (and stuff like passwords) you want to use external property files, how to do that is also explained in that section :
If you don’t like application.properties as the configuration file name you can switch to another by specifying a spring.config.name environment property. You can also refer to an explicit location using the spring.config.location environment property (comma-separated list of directory locations, or file paths).
So you use the spring.config.location environment property.
Imagine you have an external config file: application-external.yml in the conf/ dir under your home directory, just add it like this:
-Dspring.config.location=file:${home}/conf/application-external.yml as a startup parameter of your JVM.
If you have multiple files, just seperate them with a comma. Note that you can easily use external properties like this to overwrite properties, not just add them.
I would advice to test this by getting your application to work with just your internal application.yml file , and then overwrite a (test) property in your external properties file and log the value of it somewhere.
Bind Yaml properties to objects
When working with Yaml properties I usually load them with #ConfigurationProperties, which is great when working with for example lists or a more complex property structure. (Which is why you should use Yaml properties, for straightforward properties you are maybe better of using regular property files). Read this for more information: Type-Safe Configuration properties
Extra: loading these properties in IntelliJ, Maven and JUnit tests
Sometimes you want to load these properties in your maven builds or when performing tests. Or just for local development with your IDE
If you use IntelliJ for development you can easily add this by adding it to your Tomcat Run Configuration : "Run" -> "Edit Configurations" , select your run configuration under "Tomcat Server" , check the Server tab and add it under "VM Options".
To use external configuration files in your Maven build : configure the maven surefire plugin like this in your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dspring.config.location=file:${home}/conf/application-external.yml</argLine>
</configuration>
</plugin>
When running JUnit tests in IntelliJ:
Run → Edit Configurations
Defaults → JUnit
add VM Options -> -ea -Dspring.config.location=file:${home}/conf/application-external.yml
Yes, you need to use #PropertySource as shown below.
The important point here is that you need to provide the application_home property (or choose any other name) as OS environment variable or System property or you can pass as a command line argument while launching Spring boot. This property tells where the configuration file (.properties or .yaml) is exactly located (example: /usr/local/my_project/ etc..)
#Configuration
#PropertySource("file:${application_home}config.properties")//or specify yaml file
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There is a very simple way to achieve this.
Inside your original application.properties file you can just specify the following line:
spring.config.import=file:Directory_To_The_File/Property_Name.properties
It will automatically sync all the properties from the external property file.
Now lets say that you have a situation where you need to get properties from multiple property files. In that case, you can mention the same line in the external property file which in turn will take the remaining properties from the second property file and so on.
Consider the following example.
application.properties:
spring.config.import=file:Resources/Custom1.properties
Custom1.properties:
server.port=8090
.
.
.
spring.config.import=file:Resources/Custom2.properties
One of the easiest way to use externalized property file using system environment variable is, in application.properties file you can use following syntax:
spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PORT}
Now, declare above used environment variables,
export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"
This way you can use different value for same variable in different environments.
Use below code in your boot class:
#PropertySource({"classpath:omnicell-health.properties"})
use below code in your controller:
#Autowired
private Environment env;
My project structure is as below:
src/main/java -> contains java classes
src/main/resources/spring/context/application-context.xml
src/test/java -> contains J-unit test
I would like to use #ContextConfiguration annotation to load my application-context.xml
How can I load this file and how can I make sure that all beans are loaded?
I tried it using classpath and file. But nothing works for me.
I am confused when to use classpath and file. Some one please help me with this.
Thanks in advance.
#ContextConfiguration("classpath:/spring/context/application-context.xml") should work.
In conventional Maven project layout, src/main/resources contains classpath resources, therefore you should use classpath: or no prefix at all, because classpath: should be a default one in this case.
If it still doesn't work, perhaps something is wrong with your project configuration and files from src/main/resources doesn't appear in the classpath.
If context loads successfully, all beans in it should be loaded as well, otherwise context will fail to load.
Try with:
ApplicationContext APPLICATION_CONTEXT = new ClassPathXmlApplicationContext("/spring/context/application-context.xml");
If it does not work, try putting application-context.xml directly in src/main/resources and then load it with
ApplicationContext APPLICATION_CONTEXT = new ClassPathXmlApplicationContext("application-context.xml");
.I have a project that has a spring-config.xml file in src/main/webapp/WEB-INF and an applicationContext.xml file in src/test/resources. I also have an abstract test base class for my unit tests in src/test/java looks something like:
#ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
public abstract class AbstractTestBase extends AbstractTransactionalJUnit4SpringContextTests {
//Common code and fields
}
All my unit tests extends this AbstractTestBase which points to the context within the src/test/resources or should. The problem arises when running my unit tests it is pulling in the spring-config.xml file.
There are other projects my team is working on that have the same file structure, same app context setup, and run as intended, but even when I have each file in the project side by side I don't see where their file runs and this one doesn't.
I am new to spring so I don't know what it is I should be looking for.
Are there any situations where Spring or Maven would not take the app context I'm handing it given all files exist? Is there anything I might be missing?
EDIT: corrected to reflect that one file is a spring-config file.
"classpath:/applicationContext.xml" should look under src/test/resources.
But it should be noticed that using that syntax will load the first one it finds and then stop as mentioned by '#chrylis'.
I once had similar problem.
You must have been using an IDE. There must have been applicationContext.xml file in your target/test-classes/ (in Eclipse IDE) in your project directory that is a copy of your xml file under src/main/webapp/WEB-INF or xml file like it.