【问题标题】:How to map nested values to flatten out a complex data structure of json - Groovy如何映射嵌套值以展平复杂的 json 数据结构 - Groovy
【发布时间】:2018-07-06 13:54:32
【问题描述】:

拥有这样的 json - “Config.json”:

{
    "Configuration" :

      {
        "_id" :
          { "id" : 40,
            "version" : 100
          },
        "companyCode" : "AB",
        "crewType" : "STANDARD",
        "modifiedByStaffId" : "12030405",
        "lastModifiedTimestamp" : "2018-07-04T12:17:21Z",
        "offDaysAllowed" : true,
        "daysAllowed" :
          { "max" : 5,
            "min" : 1
          },
        "offDayQuota" :
          { "per" : "month",
            "value" : 20
          },
        "requestWindow" :
          { "opens" :
            {
              "value" : 1,
              "unit" : "day"
            },
            "closes" :
            {
              "value" : 2,
              "unit" : "month"
            }
          },
        "reasons" : [ "wedding", "funeral", "illness" ],
        "supportingDocuments" :
          {
            "email" : "samplemail@gmail.com",
            "canSubmit" : true
          },
        "changeReasonCode" : "TODR"
      }
  }

问题: 我收到 json 响应,然后我想更改他的嵌套值并将其发回,所以我想从这个“Config.json”文件实例化对象,并且能够轻松设置/更改并获取他的嵌套值。例如 config.setDaysAllowed_Max(4)

根据这篇文章:http://www.baeldung.com/jackson-nested-values

我尝试通过 JsonProperty 使用“Mapping with Annotations”方法,所以我有一个 Config.groovy 类:

   class OffDayConfig {

        Object configuration
        Integer id
        Integer version
        String companyCode
        String crewType
        String modifiedByStaffId
        String lastModifiedTimestamp
        boolean offDaysAllowed
        Integer daysAllowed_Max
        Integer daysAllowed_Min
        String offDayQuota_Per
        Integer offDayQuota_Value
        Integer opensValue
        String opensUnit
        Integer closesValue
        String closesUnit
        List<String> reasons
        String supportingDocumentsEmail
        String supportingDocumentsCanSubmit
        String changeReasonCode

        @SuppressWarnings("unchecked")
        @JsonProperty("configuration")
        def unpackNested(Object configuration) {
            Map<String, Integer> _id = (Map<String, Integer>) configuration._id
            this.id = _id.get("id")
            this.version = _id.get("version")

            this.companyCode = configuration.get("companyCode")
            this.crewType = configuration.get("crewType")
            this.modifiedByStaffId = configuration.get("modifiedByStaffId")
            this.lastModifiedTimestamp = configuration.get("lastModifiedTimestamp")
            this.offDaysAllowed = configuration.get("offDaysAllowed")

            Map<String, Integer> daysAllowed = (Map<String, Integer>) configuration.get("daysAllowed ")
            this.daysAllowed_Max = daysAllowed.get("daysAllowed_Max")
            this.daysAllowed_Min = daysAllowed.get("daysAllowed_Min")

            Map<String, Object> offDayQuota = (Map<String, Object>) configuration.get("offDayQuota")
            this.offDayQuota_Per = offDayQuota.get("per")
            this.offDayQuota_Value = offDayQuota.get("value")

            Map<String, Object> requestWindow = (Map<String, Object>) offDayQuota.get("requestWindow")
            Map<String, Object> opens = (Map<String, Object>) requestWindow.get("opens")
            this.opensValue = opens.get("value")
            this.opensUnit = opens.get("unit")


            Map<String, Object> closes = (Map<String, Object>) requestWindow.get("closes")
            this.closesValue = closes.get("value")
            this.closesUnit = closes.get("unit")

            this.reasons = configuration.get("reasons")

            Map<String, Object> supportingDocuments = (Map<String, Object>) configuration.get("supportingDocuments")
            this.supportingDocumentsEmail = supportingDocuments.get("email")
            this.supportingDocumentsCanSubmit = supportingDocuments.get("canSubmit")

            this.changeReasonCode = configuration.get("changeReasonCode")
        }
    }

然后我使用 ObjectMapper 来转换我们的源 JSON,它作为字符串“json”存在于测试类中:

Map offDayConfigMap = DataSource.getTestData(DataSourceType.OFF_DAY_CONFIG) //This line reads json file and creates the Map from it
String json = JsonOutput.toJson(offDayConfigMap)

OffDayConfig offDayConfig = new ObjectMapper().readerFor(OffDayConfig.class).readValue(json)

但问题出现在方法 readValue() 中。我无法弄清楚为什么以及原因是什么。这是日志:

        com.fasterxml.jackson.databind.JsonMappingException: Cannot invoke method get() on null object
        at [Source: (String)"{"Configuration":{"_id":{"id":40,"version":100},"changeReasonCode":"TODR","companyCode":"AB","crewType":"STANDARD","daysAllowed":{"max":5,"min":1},"lastModifiedTimestamp":"2018-07-04T12:17:21Z","modifiedByStaffId":"12030405","offDayQuota":{"per":"month","value":20},"offDaysAllowed":true,"reasons":["wedding","funeral","illness"],"requestWindow":{"closes":{"unit":"month","value":2},"opens":{"unit":"day","value":1}},"supportingDocuments":{"canSubmit":true,"email":"samplemail@gmail.com"}}}"; line: 1, column: 488] (through reference chain: ......................Config["Configuration"])

        at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:588)
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:576)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:134)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:287)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
        at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1608)
        at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1216)
        at ..................................Test.setupSpec(Test.groovy:42)
        Caused by: java.lang.NullPointerException: Cannot invoke method get() on null object
        at ..................................Config.unpackNested(Config.groovy:42)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:132)
        ... 5 more

点代表包。

我将不胜感激帮助或建议如何以另一种方式做到这一点,因为我需要一个好的方法来做到这一点,因为我将有几个 json 文件以这种方式处理。

【问题讨论】:

    标签: json groovy jackson


    【解决方案1】:

    只是一个快速的猜测,NPE 是由于

    Map<String, Integer> daysAllowed = (Map<String, Integer>) configuration.get("daysAllowed ")
    this.daysAllowed_Max = daysAllowed.get("daysAllowed_Max")
    this.daysAllowed_Min = daysAllowed.get("daysAllowed_Min")
    

    “daysAllowed”字符串后有一个空格,这会导致 daysAllowed 为空,因为您的 json 文件中没有正确的键来匹配“daysAllowed”,并且您采取的任何后续操作都是调用 get() on一个空对象。

    如果还没有的话,我建议使用带有调试工具的适当 IDE,并逐行遍历代码,看看会发生什么。

    【讨论】:

    • 感谢您的建议。通过调试我发现了错误。现在我需要找到一种方法将这个平面对象再次转换为相同的 json。
    • 如果我的回答对你有帮助,请考虑接受它。
    【解决方案2】:

    感谢@Boaz 的回答,我调试了我的代码,发现了 3 个错误:

    Map<String, Integer> daysAllowed = (Map<String, Integer>) configuration.get("daysAllowed ") -> the space after "daysAllowed " -> "daysAllowed"
    
    Map<String, Object> requestWindow = (Map<String, Object>) offDayQuota.get("requestWindow") -> Here I should write configuration.get("requestWindow") instead of  offDayQuota.get("requestWindow"), so "offDayQuota" -> "configuration"
    
    
    this.daysAllowed_Max = daysAllowed.get("daysAllowed_Max") -> "max" instead of "daysAllowed_Max"
    this.daysAllowed_Min = daysAllowed.get("daysAllowed_Min") -> "min" instead of "daysAllowed_Min"
    

    有效,但我不知道如何将这个平面对象再次转换为相同的 json。

    【讨论】:

      猜你喜欢
      • 2021-07-14
      • 2015-03-25
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多