Affects: since 4.1


I am trying to fix the #27020 , but meet one exists test case failed. But I really think the failed test case is a anti-use of numberic indexed map of Yaml.

https://github.com/spring-projects/spring-framework/blob/58e9b187fedf03da21c4e2270bb5335b941ccf61/spring-beans/src/test/java/org/springframework/beans/factory/config/YamlProcessorTests.java#L108-L115

In the test case, it wrapped the numberic index of yaml as a bracket escaped key and verify the final key.

Problems in code

https://github.com/spring-projects/spring-framework/blob/58e9b187fedf03da21c4e2270bb5335b941ccf61/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java#L230-L252

in Line 248 it wrap all non-string key with bracket. Is it wrong?

https://github.com/spring-projects/spring-framework/blob/58e9b187fedf03da21c4e2270bb5335b941ccf61/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlProcessor.java#L248

Comment From: ian4hu

Should Spring need reject all invalid/non-string key or only wrap key with special chars?

example yaml

root:
  1: positive integer
  -1: negative integer
  1.1: positive decimal
  -1.1: negative decimal
  true: ok

equivalent json

{
   "root": {
      "1": "positive integer",
      "-1": "negative integer",
      "1.1": "positive decimal",
      "-1.1": "negative decimal",
      "true": "ok"
   }
}

Reject all invalid/non-string key - string accepted as it is. (may contains special chars like [ ) - positive long/integer number accepted as plain toString() - negative long/integer number like -1 rejected with illegal argument - decimal like 1.1 rejected with illegal argument - char accepted as plain toString() - others accepted as plain toString(), (but may contains special chars like [ )

root:
  1: positive integer
  -1: negative integer <- illegal argument
  1.1: positive decimal <- illegal argument
  -1.1: negative decimal <- illegal argument
  true: ok

Or:

Accept all keys, but escape special key with brackets

  • string if it contains special chars like . / [ etc, wrap it with brackets like a.b -> [a.b]
  • integer number accepted as toString(), negative number will not be wrapped like -1 -> -1
  • decimal number accepted as toString() but with bracket wrapped around. -1.0 -> [-1.0] 1.0 -> [1.0]
  • other types accepted as plain toString(), wrap only when it contains special chars.

parse example yaml as bellow properties

root.1 = positive integer
root.-1 = negative integer 
root.[1.1] = positive decimal 
root.[-1.1] = negative decimal
root.true = ok

Comment From: ian4hu

related https://github.com/spring-cloud/spring-cloud-config/issues/1595

Comment From: j4zzcat

I stumbled upon this bug myself -- there's something broken also when using trailing zeros. See the following test case in Kotlin.


package bugs

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.core.env.PropertiesPropertySource
import org.springframework.core.io.InputStreamResource
import org.springframework.stereotype.Component

@SpringBootApplication
class Main

fun main(args: Array<String>) {
    runApplication<Main>(*args)
}

@Component
class Testcase {
    init {
        val testcase =
            """
               foo:
                 7: G
                 8: H
                 9: I
                 10: J

               bar:
                 07: G
                 08: H
                 09: I
                 10: J
            """.trimIndent()

        val factory = YamlPropertiesFactoryBean()
        factory.setResources(InputStreamResource(testcase.byteInputStream()))

        val p = PropertiesPropertySource("testcase", factory.getObject()!!)
        p.propertyNames.forEach(::println)
    }
}

Which produces:

bar.08   <-- doh
bar.09   <-- doh!
bar[10]  <-- ok
bar[7]   <-- ok
foo[10]  <-- ok
foo[7]   <-- ok
foo[8]   <-- ok
foo[9]   <-- ok

Comment From: snicoll

in Line 248 it wrap all non-string key with bracket. Is it wrong?

No. Please note that YamlProcessor and the companion classes are mainly intended to map a yaml configuration file to a property source. As such, it does not intend to preserve the type of intermediate elements.

Duplicates of #24608