0
votes

I am migrating a small "legacy" application to Spring Boot and ran into an issue with property placeholders in combination with a YamlPropertiesFactoryBean. The application uses Spring XML configuration.

I added a Spring Boot "main" to the project like so:

@SpringBootApplication
@ImportResource("classpath:spring-config.xml")
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

I have placed an application.yaml into /config. It is being picked up by Spring boot and I can access properties defined in it via property replacement (${some.prop}) in bean declarations in the imported spring-config.xml. E.g.

<bean id="myRouteBuilder" class="org.camelSpringBoot.test.MyRouteBuilder">
    <property name="someProp" value="${prop.from.application.yaml}"/>
</bean>

Except when using a org.springframework.beans.factory.config.YamlPropertiesFactoryBean to read an additional, external configuration file: A property for the file location in the constructor arg of a org.springframework.core.io.FileSystemResource does not get resolved:

<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
    <property name="resources">
        <list>
            <bean class="org.springframework.core.io.FileSystemResource">
                <constructor-arg value="${service.config.loc}" />
            </bean>
        </list>
    </property>
</bean>

yields

java.io.FileNotFoundException: ${service.config.loc}

If I hard-code the location of the external configuration then properties used in the external YAML file are not resolved either.

application.yaml:

security:
  keystore:
    loc:      /security/my.keystore

external config:

services:
  a:
    ssl:
      secret: ${security.keystore.loc}

java.lang.RuntimeException: Cannot open keystore/truststore ${security.keystore.loc}

Note that the error complains about the verbatim property.

The YamlPropertiesFactoryBean instance is declared in spring-config.xml like the other beans that successfully use property placeholders (meaning properties get replaced by their values). Why would it fail for the YamlPropertiesFactoryBean

Is it possible to enable placeholder resolution for the external YAML document?

1
Just adding a bean that reads a file into properties will not work. Next to that loading and resolving properties isn’t a multi passed based Solutions. So trying to add a properties object and expecting to have those resolved isn’t going to work. Also the property in your YAML is different that the placeholder you used. - M. Deinum
@M.Deinum, well, lots of things in Spring (Boot) just work. ;-) Anyway, the properties read from the YAML file also end up in the Environment as a property source. So I was wondering if the property replacement could be triggered by some clever configuration. (I don't see where the property name mismatch is? Can you be more precise or edit the question directly? Anyway, those are not the real values. The actual configuration contains application specific names.) - Ralf

1 Answers

0
votes

I do not know if it is working what you are trying to do. The Property resolving takes place after a BeanDefinition is done, and therefore only working with Spring Beans, but not arbitrary files like your yaml file.

Most build tools (gradle, maven) contain a functionality to resolve those placeholder during build time. Might that be a solution for you?