- changed status to open
parse on is a error key
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 FixedYamlResolver
to 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)
-
-
- marked as task
-
MutableMap is an interface https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-map/
yaml.loadAs
expects a JavaBean -
You can find the explanation in the PR
-
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)$")
-
- marked as minor
-
assigned issue to
-
reporter I resolve it, you are right,becaese
addImplicitResolver
is invoke inResolver
construct. soBOOL has not init.
can move this this line inside methodaddImplicitResolvers 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
-
I am sorry, I do not get your comment. A PR would explain it better.
-
reporter - changed status to resolved
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
-
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 ?
-
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 matchResolver
’s BOOL pattern, I think theResolver
’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) }
-
Well, I am afraid your question is not about SnakeYAML but about the specification.
According to the YAML 1.1 spec on is a boolean: https://yaml.org/type/bool.html
You may switch to YAML 1.2 and SnakeYAML Engine if you wish to use the latest spec (where on is a normal scalar by default)
- Log in to comment