Spring @ConfigurationProperties configuration processor not generating correct metadata for Maps with enum keys and values

Viewed 59

I need to do some lightweight attribute-based access control in a Spring Boot application.

(The background is not related to my question, but here's a brief summary: There are different types of users, different types of resources (each with attributes), and different levels of access. I need to evaluate access to resources very dynamically - hence using enums to separate permission evaluation from other logic.)

I want to store the configuration for the permissions in application.yml so I can configure it easily, and change it without making code changes.

I wanted to set this up using @ConfigurationProperties, so that the config in application.yml had autocompletion and could be softly validated. This works very nicely for other properties, but not when I start using Maps.

application.yml with my custom properties, either with an error or not being validated by IntelliJ

I can change the keys to strings, and map them in the config class (even though I lose type-completion), but the documentation in a few places indicates that that Maps should use enum, and metadata will be generated correctly - so I am confused.

I have correctly set up spring-boot-configuration-processor (it works for other properties) and it is generating the metadata JSON (see below).

MyConfig.kt

package example.myapp

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding

@ConstructorBinding
@ConfigurationProperties("my-app")
data class MyConfig(
    val permissions: Map<Role, Map<ResourceId, Set<Permission>>>,

    val owner: Map<ResourceId, Set<Permission>>
) {
    enum class Role {
        OWNER,
        VIEWER,
    }

    enum class Permission {
        VIEW,
        EDIT,
    }

    enum class ResourceId {
        ARTICLE_TITLE,
        ARTICLE_BODY,
    }
}

spring-configuration-metadata.json

{
  "groups": [
    {
      "name": "my-app",
      "type": "example.myapp.MyConfig",
      "sourceType": "example.myapp.MyConfig"
    }
  ],
  "properties": [
    {
      "name": "my-app.owner",
      "type": "java.util.Map<example.myapp.MyConfig$ResourceId,? extends java.util.Set<? extends example.myapp.MyConfig.Permission>>",
      "sourceType": "example.myapp.MyConfig"
    },
    {
      "name": "my-app.permissions",
      "type": "java.util.Map<example.myapp.MyConfig$Role,? extends java.util.Map<example.myapp.MyConfig.ResourceId,? extends java.util.Set<? extends example.myapp.MyConfig.Permission>>>",
      "sourceType": "example.myapp.MyConfig"
    }
  ],
  "hints": []
}

Versions

  • Spring Boot 2.7.1
  • Kotlin 1.7.10

Update

Changing Map<> to HashMap<> seems to help avoid the errors in the keys, but doesn't affect the values - I get a misleading warning: Cannot resolve configuration property

@ConstructorBinding
@ConfigurationProperties("my-app")
data class MyConfig(
    val permissions: HashMap<Role, HashMap<ResourceId, HashSet<Permission>>>,

    val owner: HashMap<ResourceId, HashSet<Permission>>
)

enter image description here

0 Answers
Related