Skip to content

backwards compatibility in PropertyPlaceholderHelper and PlaceholderParser in Spring Framework 6.2.x #34301

@johnf703506

Description

@johnf703506

We are currently using Spring Boot 3.3 and attempting to upgrade to Spring Boot 3.4. We have come across an issue that is the Spring core project that is introduced in version 6.2 where our existing code no longer works. The changes are in:

https://github.com/spring-projects/spring-framework/blob/6.2.x/spring-core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java
and
https://github.com/spring-projects/spring-framework/blob/6.2.x/spring-core/src/main/java/org/springframework/util/PlaceholderParser.java

We have a custom class that extends PropertySource to handle our own implementation of properties:

import org.springframework.core.env.PropertySource;

public class CustomPropertySource extends PropertySource<CustomPropertyProvider> {

    @Override 
    public Object getProperty(String propertyName) { 

       //our code here 
    } 
}

And a property in application.yaml that looks like this:

example-properties:
    property1: ${customproperty:this-is-a-custom-property}

With Spring Boot 3.3 (and Spring Framework 6.1.x), we can debug into our CustomPropertySource.getProperty() method and see that “customproperty:this-is-a-custom-property" is passed in the propertyName parameter.
With Spring Boot 3.4 (and Spring Framework 6.2.x), we can debug into our CustomPropertySource.getProperty() method and see that “customproperty" is passed in the propertyName parameter, which causes our code to fail.

One solution to this issue is to modify PlaceHolderParser. SimplePlaceholderPart.resolve() method to change from:

@Override
public String resolve(PartResolutionContext resolutionContext) {
    String value = resolveRecursively(resolutionContext);
    if (value != null) {
        return value;
    }
    else if (this.fallback != null) {
        return this.fallback;
    }
    return resolutionContext.handleUnresolvablePlaceholder(this.key, text());
}

to:

@Override
public String resolve(PartResolutionContext resolutionContext) {
    String value = resolveRecursively(resolutionContext, this.key);
    if (value != null) {
        return value;
    } else {
        value = resolveRecursively(resolutionContext, this.text());
    }
    if (value != null) {
        return value;
    } else if (this.fallback != null) {
        return this.fallback;
    }
    return resolutionContext.handleUnresolvablePlaceholder(this.key, text());
}
    

So that if the key does not find the right value, the entire text value of the property will be sent in a second call to the class that extends PropertySource.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions