【问题标题】:Groovy + JsonSlurper strange behaviourGroovy + JsonSlurper 奇怪的行为
【发布时间】:2016-03-04 21:31:17
【问题描述】:

我有以下代码来解析 JSON 文件:

@Override
Map<String, Configuration> parseJson() {
    Object configurationFile = readConfigurationFile()
    configurationFile.schemas.each { schemaProtectionInformation ->
        processing(schemaProtectionInformation)
    }
}

private Object readConfigurationFile() {
    InputStream is = getClass().getClassLoader().getResourceAsStream("test.json")
    BufferedReader reader = new BufferedReader(new InputStreamReader(is))
    return new JsonSlurper().parse(reader)
}

处理以下 JSON 文件:

{
  "schemas": [
    {
      "name": "plan_pm_test",
      "protectedDimensions": [
        {
          "name": "dActivityWbs",
          "usedToSecureFactTable": true,
          "aliasInFactTable": "PLAN_WBS",
          "levels" : ["LEVEL_1_ID","LEVEL_2_ID","LEVEL_3_ID","LEVEL_4_ID","LEVEL_5_ID","LEVEL_6_ID","LEVEL_7_ID","LEVEL_8_ID","LEVEL_9_ID"]
        },
        {
          "name": "dResponsibleOrganicUnit",
          "usedToSecureFactTable": true,
          "aliasInFactTable": "RES_ORG_UNIT",
          "levels" : ["ID","LEVEL_1_ID","LEVEL_2_ID"]
        },
        {
          "name": "dContributionOrganicUnit",
          "usedToSecureFactTable": true,
          "aliasInFactTable": "CON_ORG_UNIT",
          "levels" : ["ID","LEVEL_1_ID","LEVEL_2_ID"]
        }
      ]
    }
  ]
}

如果我执行此代码,我将收到以下错误:

Cannot cast object '[{name=plan_pm_test, protectedDimensions=[{aliasInFactTable=PLAN_WBS, levels=[LEVEL_1_ID, LEVEL_2_ID, LEVEL_3_ID, LEVEL_4_ID, LEVEL_5_ID, LEVEL_6_ID, LEVEL_7_ID, LEVEL_8_ID, LEVEL_9_ID], name=dActivityWbs, usedToSecureFactTable=true}, {aliasInFactTable=RES_ORG_UNIT, levels=[ID, LEVEL_1_ID, LEVEL_2_ID], name=dResponsibleOrganicUnit, usedToSecureFactTable=true}, {aliasInFactTable=CON_ORG_UNIT, levels=[ID, LEVEL_1_ID, LEVEL_2_ID], name=dContributionOrganicUnit, usedToSecureFactTable=true}]}]' with class 'java.util.ArrayList' to class 'java.util.Map' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.Map(groovy.json.internal.LazyMap)
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[{name=plan_pm_test, protectedDimensions=[{aliasInFactTable=PLAN_WBS, levels=[LEVEL_1_ID, LEVEL_2_ID, LEVEL_3_ID, LEVEL_4_ID, LEVEL_5_ID, LEVEL_6_ID, LEVEL_7_ID, LEVEL_8_ID, LEVEL_9_ID], name=dActivityWbs, usedToSecureFactTable=true}, {aliasInFactTable=RES_ORG_UNIT, levels=[ID, LEVEL_1_ID, LEVEL_2_ID], name=dResponsibleOrganicUnit, usedToSecureFactTable=true}, {aliasInFactTable=CON_ORG_UNIT, levels=[ID, LEVEL_1_ID, LEVEL_2_ID], name=dContributionOrganicUnit, usedToSecureFactTable=true}]}]' with class 'java.util.ArrayList' to class 'java.util.Map' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.Map(groovy.json.internal.LazyMap)
    at cern.ais.datawarehouse.baserver.mondriansecurity.common.schemaprotectionconfiguration.JsonResourceFileConfigurationRepositoryPopulator.readConfiguration(JsonResourceFileConfigurationRepositoryPopulator.groovy:23)
    at cern.ais.datawarehouse.baserver.mondriansecurity.common.schemaprotectionconfiguration.JsonResourceFileConfigurationRepositoryPopulatorTest.tes(JsonResourceFileConfigurationRepositoryPopulatorTest.groovy:12)

所以我当然开始一步步调试应用程序,看看 processing() 中的哪一部分代码抛出了这个异常。令人惊讶的是那里的所有代码都正常执行:没有抛出异常并返回结果我除外。

更让我吃惊的是,当我稍微更改第一种方法的代码时,它可以正常工作而不会产生异常。

@Override
Map<String, Configuration> readConfiguration() {
    Object configurationFile = readConfigurationFile()
    configurationFile.schemas.each { schemaProtectionInformation ->
        processing(schemaProtectionInformation)
    }
    println "test 2"
}

我不知道 println 方法如何改变那里的任何东西。当然,它不一定是 println 方法可以解决问题。所以如果我做这样的事情:

@Override
Map<String, Configuration> readConfiguration() {
    Object configurationFile = readConfigurationFile()
    configurationFile.schemas.each { schemaProtectionInformation ->
        processing(schemaProtectionInformation)
    }
    test()
}

void test() {

}

它也能正常工作(不会抛出异常)。我不知道为什么在处理 json 文件后有一些额外的代码应该在此处进行任何更改。

刚才我实际上已经把处理方法注释掉了,所以方法体如下所示。

@Override
Map<String, Configuration> readConfiguration() {
    Object configurationFile = readConfigurationFile()
    configurationFile.schemas.each { schemaProtectionInformation ->
        //processing(schemaProtectionInformation)
    }
}

即使我收到同样的异常。因此,该错误与处理方法的实现无关。

非常感谢您的意见。

【问题讨论】:

标签: json groovy jsonslurper


【解决方案1】:

在 Groovy 中,return 是隐式的,它是函数的最后一条语句。所以你的代码相当于:

@Override
Map<String, Configuration> parseJson() {
    Object configurationFile = readConfigurationFile()
    return configurationFile.schemas.each { schemaProtectionInformation ->
        processing(schemaProtectionInformation)
    }
}

each 函数返回被调用的元素。在您的情况下,schemas。但是,模式是一个集合,而不是一个映射:您会看到 ClassCastException。您的代码相当于:

@Override
Map<String, Configuration> parseJson() {
    Object configurationFile = readConfigurationFile()
    configurationFile.schemas.each { schemaProtectionInformation ->
        processing(schemaProtectionInformation)
    }
    return configurationFile.schemas
}

当你在这个语句之后添加一些东西时,你只是在创建另一个隐含的return。你应该使用明确的return configurationFile

【讨论】:

  • 好像是同时回复的。发布问题几分钟后,我意识到了这个错误。不过,非常感谢您的帮助。
【解决方案2】:

哇,对不起。这样的菜鸟错误。太糟糕了,我没有对这个类进行单元测试,因为那时我会更快地发现缺失的部分。

显然缺少的部分是返回关键字。现在的代码如下所示:

@Override
Map<String, Configuration> readConfiguration() {
    Object configurationFile = readConfigurationFile()
    configurationFile.schemas.each() { schemaProtectionInformation ->
        processSchemaDetailsFromFile(schemaProtectionInformation)
    }
    return schemasConfigurations
}

并且没有任何问题。

如果我没记错的话,这段代码是从 reloadConfiguration() 没有返回值的代码演变而来的。然后可能我更改了返回类型但忘记添加显式返回语句。由于 groovy 允许没有 return 关键字,它没有抱怨并尝试返回一些列表,然后失败导致此方法返回的指定类型的值是 map。

嗯...我责怪睡眠不足。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多