如何映射嵌套值以展平JSON的复杂数据结构-Groovy

时间:2018-07-06 13:54:32

标签: json groovy jackson

具有这样的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的使用中使用“带有注释的映射”方法,因此我有一个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文件。

2 个答案:

答案 0 :(得分: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为null,因为json文件中没有与“ daysAllowed”相匹配的适当键,并且您随后执行的任何操作都是调用{{1} }在空对象上。

我建议(如果尚未使用)带有调试工具的正确IDE,并逐行遍历代码,看看会发生什么情况。

答案 1 :(得分:0)

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

var testStr = 'Eagle'
var vowelRegex = '^[aieouAIEOU].*'
var matched = testStr.match(vowelRegex)
if(matched)
{
alert('matched');
}
else
{
alert('not matched');
}

它可以工作,但是我不知道如何再次将此平面对象转换为相同的json。