Skip to content

ConfigurationProperties initial values not restored on DELETE /actuator/env #1616

Closed

Description

@david0

Describe the bug

We are setting a configuration value via POST /actuator/env and later attempt to restore the original value by running DELETE /actuator/env.
However, this does not work — Spring does not restore the values defined in the field declaration.

Sample

@ConfigurationProperties("my-properties")
class MyProperties {
    private String name = "initial";
}

Change the value via actuator and delete the change:

curl -H 'Content-Type: application/json' --data '{"name": "my-properties.name", "value": "from-actuator"}' -X POST http://localhost:8080/actuator/env

curl -X DELETE http://localhost:8080/actuator/env

After this, the value is still from-env although I would have expected initial again.

It seems likeJavaBeanBinder is not able to do that. (This is even tested here)

Activity

  1. changed the title [-]ConfigurationProperties initial values not restore on DELETE /actutaor/env[/-] [+]ConfigurationProperties initial values not restored on DELETE /actutaor/env[/+] on Oct 24, 2025
  2. changed the title [-]ConfigurationProperties initial values not restored on DELETE /actutaor/env[/-] [+]ConfigurationProperties initial values not restored on DELETE /actuator/env[/+] on Oct 28, 2025
  3. ryanjbaxter commented on Oct 29, 2025

    @ryanjbaxter
    Contributor

    Thanks for reporting this issue, @david0. After investigating, I believe this is an expected behavior based on how Spring Boot's property binding works.

    The issue is in Spring Boot's Binder class, not in Spring Cloud Config or Spring Cloud Commons.

    When you call DELETE /actuator/env:

    1. The "manager" property source is correctly removed from the Environment
    2. ConfigurationPropertiesRebinder correctly triggers rebinding of your @ConfigurationProperties beans
    3. However, the Binder uses Java default values (null, 0, false) when properties are absent - it never uses field initializers

    Why Field Initializers Aren't Restored

    Field initializers like this:

    @ConfigurationProperties("my-properties")
    class MyProperties {
        private String name = "initial";  // Field initializer
    }

    Are only executed during object construction. During rebinding:

    • The bean is not recreated from scratch
    • Spring Boot only re-sets property values
    • The Binder has no access to field initializer values from your source code
    • When a property is absent, it uses Java defaults (null for objects, 0 for primitives)
  4. david0 commented on Nov 6, 2025

    @david0
    Author

    While I agree that your analysis is correct I do not understand why it is accepted that this is "just the way how it is".

    Its counter-intuitive and makes the use of field initialisers for @ConfigurationProperties questionable, as they will not handled correctly. At least that should be documented.

    I also think it does not has to be this way, as a fresh bean could be created and the values could be copied over. Theoretically that would work and should at least be considered.

  5. ryanjbaxter commented on Nov 7, 2025

    @ryanjbaxter
    Contributor

    It is not something Spring Cloud can address since it is behavior of the Binder in Spring Boot so if the behavior needs to change, the change needs to be made in Spring Boot

  6. wilkinsona commented on Nov 28, 2025

    @wilkinsona
    Contributor

    I don't think Boot can do anything about this. Property rebinding is a Spring Cloud feature that Boot knows nothing about.

    During rebinding:

    The bean is not recreated from scratch

    This is the crux of the problem. AFAIK, there's no way to replay a class's field initialisers on an existing instance. As a result, for rebinding to work reliably, the instance has to be recreated. For that to work, everywhere that the @ConfigurationProperties bean has been injected a proxy is required. Perhaps @RefreshScope can help here? Alternatively, perhaps Cloud can allow people to opt in to proxying of all @ConfigurationProperties beans when someone wants to use rebinding and then recreate the instance that's behind the proxy upon an EnvironmentChangedEvent.

  7. 2 remaining items

  8. david0 commented on Jan 5, 2026

    @david0
    Author

    Nice to see that its considered again.

    Would it be acceptable to do copy over the values from the new bean to the old bean? At least that works correctly for me and is not as a big change as proxying?

    var freshBean = applicationContext.getAutowireCapableBeanFactory().createBean(clazz);
    ReflectionUtils.shallowCopyFieldState(freshBean, bean);
  9. seonghyeoklee commented on Mar 7, 2026

    @seonghyeoklee

    Hi, I'd like to work on this issue.

    Before I start, I'd like to confirm the preferred approach — should I go with the shallowCopyFieldState approach, or the proxy-based instance replacement that @wilkinsona mentioned?

  10. ryanjbaxter commented on Mar 9, 2026

    @ryanjbaxter
    Contributor

    I would say the proxy approach would be my first choice I think

  11. added 2 commits that reference this issue on Mar 10, 2026
    f8fab9b
    49a9ec2
  12. added this to the 5.0.2 milestone on Mar 24, 2026
  13. moved this from In Progress to Done in 2025.1.2on Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions