Search code examples
javaspringspring-bootconfigurationproperties

Override setter in @ConfigurationProperties with list type


I am using Spring Boot 1.5.15 and I am having some trouble during the reading of a bean annotated with the annotation @ConfigurationProperties.

In details, I am trying to use the following bean.

@ConfigurationProperties(prefix = "permissions")
public class Permissions {
    private List<String> permissions;
    private Set<String> permissionsSet;

    public List<String> getPermissions() {
        return this.permissions;
    }

    public void setPermissions(List<String> permissions) {
        this.permissionsSet = new HashSet<>(permissions)
        this.permissions = permissions;
    }

    // Other code
}

The corresponding application.yml is the following.

permissions:
  permissions:
    - ROLE_1
    - ROLE_2

The problem I am facing is that the member permissionsSet is always empty. I debugged the application, and I found that Spring uses the following workflow to create the bean.

  1. Default constructor calling
  2. Setter calling with an empty list
  3. Injection of the correct value for the list after the setter calls.

Is this the right behaviour? I am trying to find any reference in the documentation, but I cannot find anything.

Is there any way to resolve this problem?

Thanks a lot.


Solution

  • Whether it's right is debatable, as you noticed, it's what happens.

    If you only have a small set of permissions (like a handful), the easiest solution would be to just have the getter return

    return Sets.newHashset(permissions) 
    

    or the like. In most cases, the performance drawback won't matter.

    If you fear performance issues you can initialize permissionsSet as null and properly initialize it the first time the getter is used (i.e. initialize it from permissions if it is null).

    Alternatively, you can try @PostConstruct (see here for official documentation) or other options to initialize the bean after construction with custom code to initialize permissionSet, but I'd consider this overkill for this example.