18

I want to escape my Spring propeties file in order to get in my bean property: ${ROOTPATH}/relativePath

I have a simple Spring config file that contains:

<context:property-placeholder location="classpath:myprops.properties" />

<bean id="myBean" class="spring.MyBean">
    <property name="myProperty" value="${myproperty}" />
</bean> 

The myprops.properties contains:

myproperty=\${ROOTPATH}/relativePath

The above setup returns: Could not resolve placeholder 'ROOTPATH'. I tried a lot of possible syntaxes but was not able to find the right one.

Honza Zidek
  • 9,204
  • 4
  • 72
  • 118
Stephane
  • 235
  • 4
  • 7

4 Answers4

18

Instead of ${myproperty} use #{'$'}{myproperty}. Simply replace $ with #{'$'}.

Manuel
  • 3,828
  • 6
  • 33
  • 48
user2428804
  • 667
  • 7
  • 11
  • No it won't work. It would resolve as `${myproperty}` injected into myBean.myProperty literally instead of `${ROOTPATH}/relativePath`. – t7tran Dec 08 '14 at 23:16
  • Depends what would you like to achieve. I guess you need to put it literally as value to myProperty. If you want to resolve ROOTPATH from somewhere e.g. system properties you can use Spring Expression Language SpEl. For example something like this: `#{ systemProperties['ROOTPATH'] }/relativePath` – user2428804 Mar 03 '15 at 09:34
6

Seems so far, that is no way to escape the ${}, however you can try below configuration to solve the problem

dollar=$

myproperty=${dollar}{myproperty}

Result for myproperty will be ${myproperty} after evaluation.

Allen Ai
  • 69
  • 1
  • 3
3

Here is a Spring ticket which asks for escaping support (still unresolved at the time of writing).

The workaround of using

$=$
myproperty=${$}{ROOTPATH}/relativePath

does provide a solution, but looks quite dirty.

Using SPEL expressions like #{'$'} did not work for me with Spring Boot 1.5.7.

Christian
  • 13,285
  • 2
  • 32
  • 49
0

Although it works, escaping the placeholder is super-ugly.

I achieved this my overriding PropertySourcesPlaceholderConfigurer.doProcessProperties and using a custom StringValueResolver

 public static class CustomPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {

    @Override
    protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) {
        StringValueResolver customValueResolver = strVal -> {
            if(strVal.startsWith("${something.")) {
                PropertySourcesPropertyResolver customPropertySourcesPropertyResolver = new PropertySourcesPropertyResolver(this.getAppliedPropertySources());
                String resolvedText = customPropertySourcesPropertyResolver.resolvePlaceholders(strVal);

                //remove the below check if you are okay with the property not being present (i.e remove if the property is optional)
                if(resolvedText.equals(strVal)) {
                    throw new RuntimeException("placeholder " + strVal + " not found");
                }
                return resolvedText;
            }
            else {
                //default behaviour
                return valueResolver.resolveStringValue(strVal);
            }
        };
        super.doProcessProperties(beanFactoryToProcess, customValueResolver);
    }
}

plugging it into the app

@Configuration
public class PlaceHolderResolverConfig
{
  @Bean
  public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
     PropertySourcesPlaceholderConfigurer placeHolderConfigurer = new CustomPropertySourcesPlaceholderConfigurer();
     placeHolderConfigurer.setLocation(new ClassPathResource("application.properties"));
    
     return placeHolderConfigurer;
  }
}

In the above example, for all properties starting with something.* nested placeholders wont be resolved.. remove the if(strVal.startsWith("${something.")) check if you want the behaviour for all properties

SatheeshJM
  • 3,575
  • 8
  • 37
  • 60