将 JSON 中找到的自定义字符串映射到 POGO 枚举案例
Mapping custom strings found in JSON to POGO enum cases
在 Grails 应用程序的上下文中,我们将 JSON 解析为命令对象。从 JSON 映射到 POGO 的自动转换失败并出现如下错误:
org.codehaus.groovy.runtime.typehandling.GroovyCastException
:
Cannot cast object '{<snip>}
' with class 'groovy.json.internal.LazyMap
' to class 'SomeCmd
' due to:
java.lang.IllegalArgumentException
: No enum constant Foo.my-bar
我把它缩小到这个简单的 Groovy MWE:
import groovy.json.JsonSlurper
enum Foo {
Bar("my-bar"),
Ista("my-ista")
final String s
private Foo(String s) {
this.s = s
}
}
class SomeCmd {
Foo foo
}
def some = new SomeCmd(new JsonSlurper().parseText('{ "foo" : "my-bar" }'))
println(some.foo)
此错误与
java.lang.IllegalArgumentException
: No enum constant Foo.my-bar
这是意料之中的 -- 到目前为止,还不错。
现在,关注the documentation, I thought adding custom coercion from String
to Foo
might resolve the issue (also from here):
enum Foo {
<snip>
static Foo fromJsonString(String s) {
return values().find { it.s == s }
}
}
def oldAsType = String.metaClass.getMetaMethod("asType", [Class] as Class[])
String.metaClass.asType = { Class type ->
type == Foo ?
Foo.byJsonString(delegate as String) :
oldAsType.invoke(delegate, [type] as Class[])
}
但是,错误仍然存在。显然,JsonSlurper
根本不使用强制转换,因为
println("my-bar" as Foo)
根据需要打印 Bar
。
这是怎么回事?我怎样才能 JsonSlurper
通过 除了 案例名称之外的东西来选择正确的枚举案例?
PS:有趣的是,如果我们将倒数第二行更改为
new JsonSlurper().parseText('{ "foo" : "my-bar" }') as SomeCmd
脚本打印 null
.
Groovy 会愉快地使用自定义 setter 来构造对象。使用问题中给出的 Foo.fromJsonString
,像这样定义 SomeCmd
:
class SomeCmd {
Foo foo
void setFoo(Object jsonObject) {
if (jsonObject == null || jsonObject instanceof Foo) {
this.foo = jsonObject
return
} else if (jsonObject instanceof String) {
Foo f = Foo.fromJsonString(jsonObject)
if ( null != f ) {
this.foo = f
return
}
}
throw new IllegalArgumentException("No Foo for $jsonObject")
}
}
然后,给定的代码根据需要打印 Bar
。
然而,这在 Grails 中将 JSON 解析为命令对象没有帮助 -- Grails 不使用强制转换,也不使用 Groovy 的映射 "magic"。参见 。
在 Grails 应用程序的上下文中,我们将 JSON 解析为命令对象。从 JSON 映射到 POGO 的自动转换失败并出现如下错误:
org.codehaus.groovy.runtime.typehandling.GroovyCastException
:
Cannot cast object '{<snip>}
' with class 'groovy.json.internal.LazyMap
' to class 'SomeCmd
' due to:
java.lang.IllegalArgumentException
: No enum constantFoo.my-bar
我把它缩小到这个简单的 Groovy MWE:
import groovy.json.JsonSlurper
enum Foo {
Bar("my-bar"),
Ista("my-ista")
final String s
private Foo(String s) {
this.s = s
}
}
class SomeCmd {
Foo foo
}
def some = new SomeCmd(new JsonSlurper().parseText('{ "foo" : "my-bar" }'))
println(some.foo)
此错误与
java.lang.IllegalArgumentException
: No enum constantFoo.my-bar
这是意料之中的 -- 到目前为止,还不错。
现在,关注the documentation, I thought adding custom coercion from String
to Foo
might resolve the issue (also from here):
enum Foo {
<snip>
static Foo fromJsonString(String s) {
return values().find { it.s == s }
}
}
def oldAsType = String.metaClass.getMetaMethod("asType", [Class] as Class[])
String.metaClass.asType = { Class type ->
type == Foo ?
Foo.byJsonString(delegate as String) :
oldAsType.invoke(delegate, [type] as Class[])
}
但是,错误仍然存在。显然,JsonSlurper
根本不使用强制转换,因为
println("my-bar" as Foo)
根据需要打印 Bar
。
这是怎么回事?我怎样才能 JsonSlurper
通过 除了 案例名称之外的东西来选择正确的枚举案例?
PS:有趣的是,如果我们将倒数第二行更改为
new JsonSlurper().parseText('{ "foo" : "my-bar" }') as SomeCmd
脚本打印 null
.
Groovy 会愉快地使用自定义 setter 来构造对象。使用问题中给出的 Foo.fromJsonString
,像这样定义 SomeCmd
:
class SomeCmd {
Foo foo
void setFoo(Object jsonObject) {
if (jsonObject == null || jsonObject instanceof Foo) {
this.foo = jsonObject
return
} else if (jsonObject instanceof String) {
Foo f = Foo.fromJsonString(jsonObject)
if ( null != f ) {
this.foo = f
return
}
}
throw new IllegalArgumentException("No Foo for $jsonObject")
}
}
然后,给定的代码根据需要打印 Bar
。
然而,这在 Grails 中将 JSON 解析为命令对象没有帮助 -- Grails 不使用强制转换,也不使用 Groovy 的映射 "magic"。参见