parse on is a error key

Issue #1080 resolved
renxue he (Ralph) created an issue

yaml version:
implementation 'org.yaml:snakeyaml:2.2'

when I parse as a MutableMap,it has an error:
for no custom resolver, I must use key true instead of original key.
test data:

    @Test
    fun `should parse right yaml for default resolver`() {
        val statusYaml = """
            name: Displayer-005
            status:
             on: true
            """.trimIndent()
        val yaml = Yaml()
        val map = yaml.loadAs(statusYaml, MutableMap::class.java)
        val name = map["name"] as String
        val status = map["status"] as LinkedHashMap<*, *>
        println(name)
        println(status)
    }

for To solve this problem,I defined a custom Resolver like this:

class FixedYamlResolver : Resolver() {

    private val BOOL = Pattern.compile("^(?:true|True|TRUE|false|False|FALSE)$")

    override fun addImplicitResolvers() {
        addImplicitResolver(Tag.BOOL, BOOL, "tTfF",10)
        /*
         * INT must be before FLOAT because the regular expression for FLOAT matches INT (see issue 130)
         * http://code.google.com/p/snakeyaml/issues/detail?id=130
         */
        addImplicitResolver(Tag.INT, INT, "-+0123456789")
        addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.")
        addImplicitResolver(Tag.MERGE, MERGE, "<", 10)
        addImplicitResolver(Tag.NULL, NULL, "~nN\u0000", 10)
        addImplicitResolver(Tag.NULL, EMPTY, null, 10)
        addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789", 50)
        // The following implicit resolver is only for documentation purposes.
        // It cannot work because plain scalars cannot start with '!', '&', or '*'.
        addImplicitResolver(Tag.YAML, YAML, "!&*", 10)
    }
}

and then I use the FixedYamlResolverto parse:

    @Test
    fun `should parse right yaml for fixed resolver`() {
        val statusYaml = """
            name: Displayer-005
            status:
             on: true
            """.trimIndent()
        val representer = Representer(DumperOptions())
        val constructor = Constructor(LoaderOptions())
        val yaml = Yaml(
            constructor, representer, initDumperOptions(representer), constructor.loadingConfig,
            FixedYamlResolver()
        )
        val map = yaml.loadAs(statusYaml, MutableMap::class.java)
        val name = map["name"] as String
        val status = map["status"] as LinkedHashMap<*, *>
        println(name)
        println(status)
    }

    private fun initDumperOptions(representer: Representer): DumperOptions? {
        val dumperOptions = DumperOptions()
        dumperOptions.defaultFlowStyle = representer.defaultFlowStyle
        dumperOptions.defaultScalarStyle = representer.defaultScalarStyle
        dumperOptions.isAllowReadOnlyProperties =
            representer.propertyUtils.isAllowReadOnlyProperties
        dumperOptions.timeZone = representer.timeZone
        return dumperOptions
    }

but even if I use FixedYamlResolver,run the test function also occour a error, and I have no idea to solve it,hope your answer, thanks. the error is this:

Cannot invoke "java.util.regex.Pattern.matcher(java.lang.CharSequence)" because "regexp" is null
java.lang.NullPointerException: Cannot invoke "java.util.regex.Pattern.matcher(java.lang.CharSequence)" because "regexp" is null
    at org.yaml.snakeyaml.resolver.Resolver.resolve(Resolver.java:133)
    at org.yaml.snakeyaml.composer.Composer.composeScalarNode(Composer.java:223)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:205)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:369)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:348)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:323)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:209)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:369)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:348)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:323)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:209)
    at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:131)
    at org.yaml.snakeyaml.composer.Composer.getSingleNode(Composer.java:157)
    at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:178)
    at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:493)
    at org.yaml.snakeyaml.Yaml.loadAs(Yaml.java:473)
    at com.namespace.test.SnakeYamlTest.should parse right yaml for fixed resolver(SnakeYamlTest.kt:40)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)

Comments (12)

  1. Andrey Somov

    Since Kotlin does not have static members, you can move this this line inside method addImplicitResolvers

    private val BOOL = Pattern.compile("^(?:true|True|TRUE|false|False|FALSE)$")

  2. renxue he (Ralph) reporter

    I resolve it, you are right,becaese addImplicitResolver is invoke in Resolver construct. so BOOL has not init.can move this this line inside method addImplicitResolvers or define

    a companion object to declare it. thank your answer.

    Despite this, I think this shouldn't be the case when parsing keys. Although you define it this way to be able to adapt to Boolean types that express different meanings when parsing. But I think it should be used only to parse values

  3. renxue he (Ralph) reporter

    I resolve it, you are right,becaese addImplicitResolver is invoke in Resolver construct. so BOOL has not init.can move this this line inside method addImplicitResolvers or define a companion object in custom resolver class to declare it. thank your answer.

    I think this shouldn't be the case when parsing keys.,although you define it this way to be able to adapt to Boolean types that express different meanings when parsing. I think it should be used only to parse values

  4. Andrey Somov

    sorry, when you copy and paste the same text it does not help. I do not get your explanation.

    Can you please provide aPR with the code proposal ?

  5. renxue he (Ralph) reporter

    I mean in the following test code, if I don't have a custom Resolver.It should be parsed to the correct key in map, key of map should not match Resolver’s BOOL pattern, I think the Resolver’s BOOL pattern is just for key in map’s value.

    test code:

    @Test
        fun `should parse right yaml for default resolver`() {
            val statusYaml = """
                name: Displayer-005
                status:
                 on: true
                """.trimIndent()
            val yaml = Yaml()
            val map = yaml.loadAs(statusYaml, MutableMap::class.java)
            val name = map["name"] as String
            val status = map["status"] as LinkedHashMap<*, *>
            println(name)
            println(status)
            val on = status[true] //original code is val on=status["on"]
            println(on)
        }
    

  6. Log in to comment