properties not loaded from external configuration, when additional config location is provided from command line

Viewed 1375

I am using spring-boot 2.2.7.RELEASE

In the controller I want to get some values from external config file. But the application does not start even though the properties are available in the external config.

could you suggest how to load only specific properties from external config.

NOTE: I also tried spring.config.additional-location, and it is not working

Thanks


Controller

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ExternalPropTestController {

    @Value("${com.x.db.url}")
    private String url;

    @Value("${com.x.db.secret}")
    private String secret;

    @GetMapping("/")
    public ResponseEntity<String> greet() {
        return new ResponseEntity<>(url+" : "+secret, HttpStatus.OK);
    }
}

config.yml

com:
  x:
    db:
      url: external url
      secret: external secret

Command to start the application

java -jar application.jar -Dspring-boot.run.arguments=--spring.config.location=file:///C://some-external-path//config//config.yml


Getting below error, while starting the application

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'externalPropTestController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'com.x.db.url' in value "${com.x.db.url}" at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:405) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:895) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at com.x.y.CrewDocServiceApp.main(CrewDocServiceApp.java:65) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) at org.springframework.boot.loader.Launcher.launch(Launcher.java:51) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52) Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'com.x.db.url' in value "${com.x.db.url}" at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178) at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124) at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236) at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210) at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175) at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:912) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ... 23 common frames omitted

3 Answers

As per documentation, SpringApplication converts any command line option arguments (that is, arguments starting with --, such as --server.port=9000) to a property and adds them to the Spring Environment.

-D works when running via maven. Try: java -jar application.jar --spring.config.location=file:///C://your//path//config.yml.

Via maven: mvn spring-boot:run -Dspring.config.location="file:///C://your//path//config.yml"

For me this fails:

java -jar application.jar -Dspring.config.location=/config/config.yml

But this works:

java -Dspring.config.location=/config/config.yml -jar application.jar

I suspect the JVM is passing the -D as an arg to main() for the former rather then using it to set the JVM environment for spring boot.

This is the behaviour I'm observing on openjdk-17 / alpine anyway...

java --version
openjdk 17-ea 2021-09-14
OpenJDK Runtime Environment (build 17-ea+14)
OpenJDK 64-Bit Server VM (build 17-ea+14, mixed mode, sharing)

try absolute path instead of relative path, to specify location of external property

Related