Groovy/Grails 字符串中“\”转义字符的激增
Groovy/Grails Proliferation of "\" escape character in a string
这是一个相当奇怪的问题。我正在集成测试 Grails 服务和关联域 class。该域 class 的一个 属性 是一个包含 JSON 的 String
。数据库字段也是 json
,并且有一个自定义的 Hibernate 值类型可以执行必要的转换。它已经在另一个领域的生产中工作多年 class。
class MyDomain {
String data
static mapping = {
data type: StringJsonUserType
}
}
到目前为止一切顺利。在我的测试中,我模拟了一个输入对象到我的服务方法,最终将包含 return 所需的 JSON 字符串。
private MockedClass mockClass() {
// JsonRepresentable declares asJson() method.
def data = GroovyMock(JsonRepresentable)
data.asJson() >> "{\"content\":\"irrelevant\"}"
def mockClass = GroovyMock(MockedClass)
mockClass.getData() >> data
return mockClass
}
服务方式(简体):
void persist(MockedClass mock) {
String string = mock.data.asJson()
def domain = new MyDomain(data: mock.data.asJson())
domain.save()
}
当我使用调试器进入这段代码时,我可以立即看到字符串已从 string
变量中的 {"content":"irrelevant"}
变为 domain
中的 "{\"content\":\"irrelevant\"}"
变量。
现在合乎逻辑的是,在我的测试中,保存域 class 字符串的比较与模拟输入不匹配。
这是 MyDomain.data
从数据库中读取数据时的样子:
"\"\\"{\\\\"content\\\\":\\\\"irrelevant\\\\"}\\"\""
这是用 new JsonSlurper().parseText(MyDomain.data)
:
解析的同一个字符串
"\"{\\"content\\":\\"irrelevant\\"}\""
这是使用 JsonSlurper(如上)解析的模拟字符串:
[content:irrelevant]
显然最后一个例子是我所期望的。谁能告诉我为什么 Groovy/Grails 会在我的简单且正确转义的字符串中添加大量糟糕的 \\ ?我什至可以尝试 Groovy 字符串 '{"content":"irrelevant"}'
但这没有丝毫区别。
只是偶然(在寻找重命名包后出现的其他一些奇怪问题时)我发现了导致问题的原因。在我的域 class 中,我不仅有 String
属性,而且 getter 和 setter return 一个 JSON 对象从该字符串或接受一个 JSON 对象并将其转换为一个字符串。
class MyDomain {
String data
static mapping = {
data type: StringJsonUserType
}
static transients = ['dataJson']
def getDataJson() {
return new JsonSlurper().parseText(data)
}
void setDataJson(def data) {
data = JsonOutput.toJson(data)
}
}
不幸的是,我在 setDataJson
中打错了字。它的名称是 setData
,因此在服务方法中它被用作我的 String
的 setter。
void persist(MockedClass mock) {
String string = mock.data.asJson()
def domain = new MyDomain(data: mock.data.asJson())
domain.save()
}
这意味着 JsonOutput.toJson(data)
将我的 JSON 字符串转换为另一个 JSON 字符串,这就是所有其他转义字符的来源。
故事的寓意:切换到在编译时强制执行类型系统的正确编译语言。
这是一个相当奇怪的问题。我正在集成测试 Grails 服务和关联域 class。该域 class 的一个 属性 是一个包含 JSON 的 String
。数据库字段也是 json
,并且有一个自定义的 Hibernate 值类型可以执行必要的转换。它已经在另一个领域的生产中工作多年 class。
class MyDomain {
String data
static mapping = {
data type: StringJsonUserType
}
}
到目前为止一切顺利。在我的测试中,我模拟了一个输入对象到我的服务方法,最终将包含 return 所需的 JSON 字符串。
private MockedClass mockClass() {
// JsonRepresentable declares asJson() method.
def data = GroovyMock(JsonRepresentable)
data.asJson() >> "{\"content\":\"irrelevant\"}"
def mockClass = GroovyMock(MockedClass)
mockClass.getData() >> data
return mockClass
}
服务方式(简体):
void persist(MockedClass mock) {
String string = mock.data.asJson()
def domain = new MyDomain(data: mock.data.asJson())
domain.save()
}
当我使用调试器进入这段代码时,我可以立即看到字符串已从 string
变量中的 {"content":"irrelevant"}
变为 domain
中的 "{\"content\":\"irrelevant\"}"
变量。
现在合乎逻辑的是,在我的测试中,保存域 class 字符串的比较与模拟输入不匹配。
这是 MyDomain.data
从数据库中读取数据时的样子:
"\"\\"{\\\\"content\\\\":\\\\"irrelevant\\\\"}\\"\""
这是用 new JsonSlurper().parseText(MyDomain.data)
:
"\"{\\"content\\":\\"irrelevant\\"}\""
这是使用 JsonSlurper(如上)解析的模拟字符串:
[content:irrelevant]
显然最后一个例子是我所期望的。谁能告诉我为什么 Groovy/Grails 会在我的简单且正确转义的字符串中添加大量糟糕的 \\ ?我什至可以尝试 Groovy 字符串 '{"content":"irrelevant"}'
但这没有丝毫区别。
只是偶然(在寻找重命名包后出现的其他一些奇怪问题时)我发现了导致问题的原因。在我的域 class 中,我不仅有 String
属性,而且 getter 和 setter return 一个 JSON 对象从该字符串或接受一个 JSON 对象并将其转换为一个字符串。
class MyDomain {
String data
static mapping = {
data type: StringJsonUserType
}
static transients = ['dataJson']
def getDataJson() {
return new JsonSlurper().parseText(data)
}
void setDataJson(def data) {
data = JsonOutput.toJson(data)
}
}
不幸的是,我在 setDataJson
中打错了字。它的名称是 setData
,因此在服务方法中它被用作我的 String
的 setter。
void persist(MockedClass mock) {
String string = mock.data.asJson()
def domain = new MyDomain(data: mock.data.asJson())
domain.save()
}
这意味着 JsonOutput.toJson(data)
将我的 JSON 字符串转换为另一个 JSON 字符串,这就是所有其他转义字符的来源。
故事的寓意:切换到在编译时强制执行类型系统的正确编译语言。