Spring Boot YAML binding: fail when using yml extension - java

i cannot start my spring-boot application, because an exception with the following messagge is thrown"Error creating bean with name 'application': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'tracer.datadog' in value
The reason is that spring-boot cannot find the "tracer.datadog" prop specificied on the application class:
#SpringBootApplication
#EnableMongoAuditing
public class Application {
#Value("${tracer.datadog}")
private boolean datadog;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#PostConstruct
private void jaegerTracer() {
if (!datadog) {
GlobalTracer.registerIfAbsent(Configuration.fromEnv().getTracer());
}
}
}
But that property is correctly defined over the application.yml file:
tracer:
datadog: true
However, changing the extension to .YAML spring-boot "find" the file and the application starts fine.
Does anyone can tell me how can i do to solve this problem and use the .yml extension? using the .yaml extension is not a possibility because of company standards

Related

How to get properties from .env file in spring boot test

I am trying to setup tests for my spring-boot application. In regular execution I get some values from .env file that I've specified in run configuration and get them like so:
#Value("${jdbc.url}")
private String jdbcUrl;
But when I try to run the simplest of tests, it fails with the exception :
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext........
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaConfig': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'jdbc.url' in value "${jdbc.url}"
How do I load properties from the environment in SpringBootTest?
Here's my test:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {App.class})
public class TestingWebApplicationTest {
#Test
public void contextLoads() {
}
}
Try adding your property to this location /src/test/resources/application-test.properties
Add an #ActiveProfiles("test") annotation on the test class and it should be picked up.
See screenshot below;
You can use a profile specific application-{profile}.properties file

How to make Spring Boot Test under JUnit 5 resolve indented/hierarchical properties externalized on a YAML file

How to make Spring Boot Test under JUnit 5 resolve indented/hierarchical properties externalized on a YAML file?
I would like to write tests to validate some logic that depends on Environment.getProperty(String key):
#ExtendWith(SpringExtension.class)
class PropertiesReolution_SO_IT {
#Nested
#TestPropertySource(locations = "classpath:application-test.yml")
public class ViaYamlFile {
#Autowired
private Environment env;
#Test
void testGetDottedHierarchicalProperty() throws Exception {
final String key = "dotted.hierarchical.property";
assertNotNull(this.env.getProperty(key));
assertEquals("application-test.yml", this.env.getProperty(key));
}
}
}
The dotted.hierarchical.property property is defined on the application-test.yml YAML file like this:
dotted:
hierarchical:
property: application-test.yml
The test case fails with the property evaluating to null. I am locked to spring-boot 1.5.8.RELEASE, so I am using org.springframework.test:spring-test-junit5. I created a Gist with the full example.

#TestPropertySource Class Could not resolve placeholder

I'm creating a TestClass using a class Propiedades which has #PropertySource annotation.
#Component
#PropertySource("file:${services.properties}test-app/.properties")
public class Propiedades {
#Value("${db.name}")
public String dbName;
#Value("${db.jndi}")
public String dbJNDI;
#Value("${db.owner}")
public String dbOwner;
}
As you can see I'm loading the .properties file from a external location relative to the server where the app is deployed. services.properties is a env variable for the server which has a route to a specific folder.
Here is my test class
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = Propiedades.class)
#TestPropertySource(locations = "/application-test.properties")
public class IncidenciaServicioServiceImplTest {
#Autowired
Propiedades propiedades;
#Test
public void isPropertySetup() {
String output = propiedades.dbName;
Assert.assertEquals("testDb", output);
}
}
When running the test I get the following error.
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [Propiedades]; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'services.properties' in value "file:${services.properties}test-app/.properties"
Why is it trying to load the properties from that path?, shouldn't it be reading from src/test/resources/application-test.properties?
As far as I know Spring does not work like you expect. It always tries to load properties specified in #PropertySource first then overrides them with values provided with #TestPropertySource annotation.
So one of the ways to workaround your issue is to use ignoreResourceNotFound flag for #PropertySource annotation:
#PropertySource("file:${services.properties}test-app/.properties", ignoreResourceNotFound = true)
public class Propiedades {
// ... your properties
}
In this case Spring will ignore the fact it can not find the properties specified with #PropertySource and continue using values from #TestPropertySource
Or alternatively, you need to provide value for your ${services.properties} env variable while tests run so it is resolved to correct path to property file.

How to make sure Flyway loads before my bean?

I have a Spring Boot application in which a Bean loads configuration-data from the database.
Right now I set up this Bean in the Configuration class. But it seems it loads before Flyway.
How to make sure Flyway has finished it's job before my beans get loaded?
You can initialize it before you start Spring Boot application:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
// Init Flyway here
SpringApplication.run(Application.class, args);
}
}
Second option is to use #DependsOn annotation for your beans depending on Flyway.

Spring boot war file does not work on tomcat

I added spring boot to a existing webapp. When i run the command
java -jar -Denvironment.type=dev myfile.war
Every things goes fine. But if I deploy on tomcat, for some reason a get a very big exception.
Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath.
I am using mongodb and I do not have any datasource configured on my application context. I also extended SpringBootServletInitializer
#SpringBootApplication
public class AdminApp extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(AdminApp.class);
}
public static void main(String[] args) {
SpringApplication.run(AdminApp.class, args);
}
}
Any clue what can it be?
My properties file
database.url=localhost
database.port=27017
database.name=dbname
database.username=admin
database.password=admin
Update: I also have this class the says which property file should be used.
#Configuration
#PropertySource("classpath:application-${environment.type}.properties")
public class PropertyWithJavaConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
The error is thrown in DataSourceProperties.getDriverClassName() method. Find below the source code of the same from spring distribution:
if (!StringUtils.hasText(driverClassName)) {
throw new BeanCreationException(
"Cannot determine embedded database driver class for database type "
+ this.embeddedDatabaseConnection
+ ". If you want an embedded "
+ "database please put a supported one on the classpath.");
}
Spring throws this error when spring.datasource.driverClassName property is empty. So to fix this error, make sure that the application.properties is in the classpath.
So, after digging a lot on the dependencies I noticed that I had spring-orm and spring-jdbc even though I was not using. I removed them and everything worked fine for embedded and local tomcat.
But I still can not understand why before worked just for embedded tomcat.

Categories