SpringBootTest doesn't import local properties - java

I am running full app test and would like to read in all of the properties for my app from src/test/resources but when I add the #TestPropertySource and locations, the app still fails to load.
In production, my config is hosted on an external server and I am able to successfully load the config for local testing with this in the boostrap.yml: spring.cloud.config.uri: {pathToDevelopmentConfigServer} However, when I remove that in favor of trying to read config locally, I can't get load the app.
My setup:
Test class:
#SpringBootTest
#EnableConfigurationProperties
#TestPropertySource(locations = {"classpath:MyApp.yaml", "classpath:MyApp-test.yaml"})
#ActiveProfiles(profiles = {"default", "test"})
#ContextConfiguration(classes = {MyAppProperties.class})
public class MyAppTestClass {
#Test
public void myTest(){
assertTrue(true); //dummy test just to have one for now
}
}
Configuration class:
#Configuration
#ConfigurationProperties(prefix = "test-config")
#Validated
public class MyAppProperties {
#NotNull
private String myPropertyValue;
#NotNull
private Map<String, String> myPropertyMap;
// Getters & Setters
}
Config file (MyApp-test.yaml):
test-config:
myPropertyValue: "testValue"
myPropertyMap:
mapKey: "myMapTestValue"
However, when I try to run this, I get this error:
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under '-test' to com.c.taylor.properties.MyAppProperties$$EnhancerBySpringCGLIB$$fd769f1a failed:
Property: test-config.myPropertyValue
Value: null
Reason: must not be null
Property: test-config.myPropertyMap
Value: null
Reason: must not be null
Action:
Update your application's configuration
I've read several docs about how to load properties into a SpringBootTest, but just haven't had any sort of luck.
Thanks in advance.
edit:
src/main/resources/bootstrap.yml file:
---
spring:
application:
name: MyApp
cloud:
config:
uri: {pathToDevelopmentConfigServer}
enabled: false

Related

Why spring boot boot not indicates that connection string removed from yml file?

I work on a java spring boot project.
I have an application.yml file that contains the connection string:
spring:
data:
mongodb:
uri: mongodb://localhost:27017/development
I comment on connection string rows in the application.yml file:
#spring:
# data:
# mongodb:
# uri: mongodb://localhost:27017/development
And then I rebuild the project and trigger repository functions.
To my surprise, I do not get any exceptions or errors while the repositories are executed and application.yml has commented connection string.
The result that I get from repository functions is an empty result.
So my question is very simple, why i do not get any indications on a runtime that the connection string is removed does spring create some default connection in case it cannot find the conn string in yml file?
I can't say if there is anything specific with Mongo, but for Spring in general you can create typesafe config and validate it on startup.
application.yml
myapp:
mongo-uri: mongodb://localhost:27017/development
spring:
data:
mongodb:
uri: ${myapp.mongo-uri}
MyAppProperties.java
#Validated
#ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
#NotEmpty
private String mongoUri;
// accessors
}
In #Configuration's or #SpringBootApplication
#EnableConfigurationProperties(MyAppProperties.class)
The key things are #Validated and #NotEmpty. You will get startup error if ${myapp.mongo-uri} is not provided.

Spring #Value not able to get value from YAML [duplicate]

I need to load a property from a .yml file, which contains the path to a folder where the application can read files from.
I'm using the following code to inject the property:
#Value("${files.upload.baseDir}")
private String pathToFileFolder;
The .yml file for development is located under src/main/resources/config/application.yml, im running the application with the following command in production, to override the development settings:
java -jar app.jar --spring.config.location=/path/to/application-production.yml
The Spring Boot documentation says:
SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment:
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
As well as:
You can also use YAML ('.yml') files as an alternative to '.properties'.
The .yml file contains:
{...}
files:
upload:
baseDir: /Users/Thomas/Code/IdeaProjects/project1/files
{...}
And my Application class is annotated with:
#SpringBootApplication
#EnableCaching
When I run the application, i get an exception:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'files.upload.baseDir' in string value "${files.upload.baseDir}"
Do I have to use the YamlPropertySourceLoader class or add a special annotation to enable the support for .yml in Spring Boot?
Edit:
The .yml file contains some other properties, which get successfully loaded by Spring Boot like dataSource.XXXor hibernate.XXX.
For example: application.yml
key:
name: description here
Your Class:
#Value("${key.name}")
private String abc;
M. Deinum is right, the setup i've provided is working - the yml file was indented wrong, so the property couldn't be found.
I found the above wasn't working for me, because I tried to access the variable in a constructor. But at construction, the value is not injected yet.
Eventually I got it to work using this workaround: https://mrhaki.blogspot.com/2015/04/spring-sweets-using-value-for.html
Maybe this is helpful to others.
For me a duplicate key in the property file caused this...
I used same key unknowingly in large yml file.
key:
key1: value
key2: value
key:
key3: value
In yml properties file :
xxxx:
page:
rowSize: 1000
Create your Yaml properties config class :
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "xxxx")
public class YmlPropertiesConfig {
private Page page;
public Page getPage() {
return page;
}
public void setPage(Page page) {
this.page = page;
}
public class Page {
private Integer rowSize;
public Integer getRowSize() {
return rowSize;
}
public void setRowSize(Integer rowSize) {
this.rowSize = rowSize;
}
}
}
Finally get it and use it :
public class XXXXController {
#Autowired
private YmlPropertiesConfig ymlProperties;
public String getIt(){
Integer pageRowSize = ymlProperties.getPage().getRowSize();
}
}
I've got that issue Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder cause I've set test spring boot profile in properties.yaml.
Spring can't find properties for test profile when run app with no profile.
So remove spring boot profile from properties or yaml or run app with enabled profile.
Configuration file example is below:
#Configuration
public class AppConfig {
#Value("${prop.foo}")
private String foo;
#Value("${prop.bar}")
private String bar;
#Bean
BeanExample beanExample() {
return new BeanExample(foo, bar);
}
}
For those who have problems with a #RestController, I do it as follows:
#Autowired
#Value("${google.recaptcha}")
private String keyRecaptcha;
My properties file was mistakenly named applcation.properties as it was auto-generated by the Spring initializer. But I added the properties there in the .yml format and they were not retrieved with the same error.
When I renamed the file to application.yml, it started working.

Spring DataSource password in separate properties file causes "Failed to determine a suitable driver class"

I have the following Spring configuration
myprefix.systems[0].name=Some System
myprefix.systems[0].datasource.driverclassname=oracle.jdbc.OracleDriver
myprefix.systems[0].datasource.url=jdbc:oracle:thin:#foo:1521/bar
myprefix.systems[0].datasource.username=username
myprefix.systems[0].datasource.password=password
Which is configured into the following class (annotations are lombok and Spring).
#Configuration
#ConfigurationProperties("myprefix")
public class SystemConfig {
#Getter
#Setter
public static class ConfiguredSystem {
private final DataSourceProperties datasource = new DataSourceProperties();
private String name;
public JdbcTemplate getTemplate() {
return new JdbcTemplate(datasource.initializeDataSourceBuilder().build());
}
}
#Getter
private final List<ConfiguredSystem> systems = new ArrayList<>();
#Bean
public List<ConfiguredSystem> allSystems() {
return Collections.unmodifiableList(tradingSystems);
}
}
This works just fine when all the properties are in one application.properties file. The application starts up properly.
I am trying to move the password line into it's own application-secret.properties file, and keep the other properties in the main application.properties file.
myprefix.systems[0].datasource.password=password
I run with
-Dspring.config.location="C:/my/app/dir/conf/"
-Dspring.profiles.active=secret
However, when I do this I get the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (the profiles secret are currently active).
| o.s.b.d.LoggingFailureAnalysisReporter [main]
After putting a breakpoint in getTemplate, it seems the DataSourceProperties only contains the password and none of the other properties. I presume Spring cannot do list comprehension (for lack of a better term), myprefix.systems[0]... across different files?
This won't answer why the initial solution (merging myprefix.systems[0].datasource.password) did not work, but you may solve your problem by:
Creating a db.password property in the application-secret.properties
Use ${db.password} in application.properties.

Spring boot how to pick externalized spring properties file

I have this configurations which needs to be used for a spring boot application.
server.port=8085
server.servlet.context-path=/authserver
#data source
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=<url>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
By default spring-boot picks up up the application.properties file located in src/main/resources/
I want to alter this path and direct spring boot to different application.properties file
I can achieve this using
java -jar app.jar --spring.config.location=classpath:/another-location.properties
Is there any any alternative solution I can achieve this without passing args through command line?
I was using this
#PropertySource("file:C:\Users\test\.test\test.properties")
#ConfigurationProperties(prefix = "spring")
public class Configuration {
private String ddlAuto;
private String url;
private String username;
private String password;
private String driverClassName;
}
in my Main class
#SpringBootApplication
#EnableConfigurationProperties(Configuration.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There after I tried executing the app commenting out all datasource properties in application.properties under src/main/resources/
But it keeps giving me the error mentioned bellow and application fails to start
I was referring this tutorial : https://www.mkyong.com/spring-boot/spring-boot-configurationproperties-example/
but as it's mentioned I get this error when i start the spring boot application
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException:
Any help on this would be appreciated
The recommended way to have externalized properties is to use the spring.config.location system property, by starting your application like so:
java -jar -Dspring.config.location=/path/to/my/file.properties app.jar
The reason for this is that you don't add coupling between your code and your filesystem hierarchy.
Before Spring Boot 2.0 this property is additive, meaning that it will complement the default locations. After Spring Boot 2.0, spring.config.location replaces the default locations (e.g. classpath src/main/resources/application.properties). To keep the additive behaviour after 2.0, use spring.config.additional-location instead.
Please see here for official documentation on this matter.
I am able to make it work properly on Spring Boot 2.1.2.RELEASE. This is what I have done:
I have a test.properties in my /tmp folder with the following content:
test.myprop=hello
I also have the usual property file in the resources folder:
myprop=world
I have created a class for the custom property file:
#Configuration
#PropertySource("file:/tmp/test.properties")
#ConfigurationProperties(prefix = "test")
public class TestConfig {
private String myprop;
public String getMyprop() {
return myprop;
}
public void setMyprop(String myprop) {
this.myprop = myprop;
}
}
And then in my main class I have enabled to configuration properties:
#EnableConfigurationProperties(TestConfig.class)
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Now I have this test controller:
#RestController
public class TestController {
#Value("${test.myprop}")
private String externalisedProp;
#Value("${myprop}")
private String prop;
#GetMapping("test")
public void test() {
System.out.println("externalised: " + externalisedProp);
System.out.println("not externalised" + prop);
}
}
Which, once called, is properly printing:
externalised: hello
not externalised: world
My TestConfig class is in the same package as the MyApp main class.
What I have done is very similar, almost identical, to your solution, are you sure your path is correct? Also, I can see that the content of your property file is not matching what you have in your config class, the prefix is different. Maybe that is the problem?
Edit:
I have tried to remove the #Configuration annotation from my property class (which you do not have as well) and it is not able to pick up the externalised properties anymore. The error is different though but you should try to add it.

Spring Boot integration tests doesn't read properties files

I would like to create integration test in which Spring Boot will read a value from .properties file using #Value annotation.
But every time I'm running test my assertion fails because Spring is unable to read the value:
org.junit.ComparisonFailure:
Expected :works!
Actual :${test}
My test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebTests.ConfigurationClass.class, WebTests.ClassToTest.class})
public class WebTests {
#Configuration
#ActiveProfiles("test")
static class ConfigurationClass {}
#Component
static class ClassToTest{
#Value("${test}")
private String test;
}
#Autowired
private ClassToTest config;
#Test
public void testTransferService() {
Assert.assertEquals(config.test, "works!");
}
}
application-test.properties under src/main/resource package contains:
test=works!
What can be the reason of that behavior and how can I fix it?
Any help highly appreciated.
You should load the application-test.properties using #PropertySource or #TestPropertySource
#RunWith(SpringJUnit4ClassRunner.class)
#TestPropertySource(locations="classpath:application-test.properties")
#ContextConfiguration(classes = {WebTests.ConfigurationClass.class, WebTests.ClassToTest.class})
public class WebTests {
}
for more info: Look into this Override default Spring-Boot application.properties settings in Junit Test
Besides the above marked correct answer, there is another nature way to load application-test.properties: Set your test run "profile" to "test".
Mark your test cases with:
#ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
application-xxxx.properties is a naming convention for properties of different "profile".
This file application-xxxx.properties should be placed in src/main/resources folder.
"Profile" is also useful in bean configuration.

Categories

Resources