【问题标题】:Groovy/Grails Proliferation of "\" escape character in a stringGroovy/Grails 字符串中“\”转义字符的扩散
【发布时间】:2019-03-04 06:30:15
【问题描述】:

这是一个相当奇怪的问题。我正在集成测试 Grails 服务和相关的域类。该域类的一个属性是包含 JSON 的 String。数据库字段也是json,并且有一个自定义的 Hibernate 值类型可以执行必要的转换。它已经在另一个领域类的生产环境中工作了多年。

class MyDomain {
    String data
    static mapping = {
        data type: StringJsonUserType
    }
}

到目前为止一切顺利。在我的测试中,我将一个输入对象模拟到我的服务方法中,最终将包含并返回所需的 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\"}"

现在唯一合乎逻辑的是,在我的测试中,保存的域类字符串的比较与模拟输入不匹配。

这是从数据库中读取MyDomain.data 数据时的样子:

"\"\\\"{\\\\\\\"content\\\\\\\":\\\\\\\"irrelevant\\\\\\\"}\\\"\""

这是用new JsonSlurper().parseText(MyDomain.data)解析的相同字符串:

"\"{\\\"content\\\":\\\"irrelevant\\\"}\""

这是用 JsonSlurper 解析的模拟字符串(如上):

[content:irrelevant]

显然最后一个例子是我所期望的。谁能告诉我为什么 Groovy/Grails 会在我的简单且正确转义的字符串中添加大量糟糕的 \\ ?我什至可以尝试使用 Groovy 字符串 '{"content":"irrelevant"}',但这并没有丝毫区别。

【问题讨论】:

    标签: testing grails groovy


    【解决方案1】:

    只是偶然(在寻找重命名包后出现的其他一些奇怪问题时)我发现了导致问题的原因。在我的域类中,我不仅有 String 属性,还有从该字符串返回 JSON 对象或接受 JSON 对象并将其转换为字符串的瞬态 getter 和 setter。

    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 的设置器。

    void persist(MockedClass mock) {
        String string = mock.data.asJson()
        def domain = new MyDomain(data: mock.data.asJson())
        domain.save()
    }
    

    这意味着JsonOutput.toJson(data) 将我的 JSON 字符串转换为另一个 JSON 字符串,这就是所有其他转义字符的来源。

    故事的精神:切换到正确编译的语言,在编译时强制执行类型系统。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-11
      • 2012-05-31
      • 2011-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-09
      相关资源
      最近更新 更多