【问题标题】:How to parse a json with dynamic property name in java?如何在java中解析具有动态属性名称的json?
【发布时间】:2022-01-13 20:42:19
【问题描述】:

我需要在我的代码中使用和解析来自 CRM 系统的传入 json。我使用 RestTemplate 来做到这一点。因此 CRM 系统的响应如下所示。

{ "GvyArEFkg6JX6wI": {
     "entityId": "GvyArEFkg6JX6wI",
     "mergePolicy": {
         "id": "9245a39d-fe1a-4b33-acab-9bc5cbabf37c"
     }
    }
}

现在的问题是动态的属性名称(在本例中为“GvyArEFkg6JX6wI”),在下一个响应中它将是另一个字符串。在这种情况下,我该如何解析这个 json,因为这不是固定的?我尝试使用jsonGetter,但它只是将它包裹在另一个块上,仍然无法解决解析响应的问题。

AdobeResponseDto.class

@Builder
@ToString
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
public class AdobeResponseDto {
    public Map<String, AdobeResponseFinal> adobeResponseWrapper = new HashMap<>();

    @JsonAnySetter
    public void setAdobeResponseWrapper(String name, AdobeResponseFinal value) {
        adobeResponseWrapper.put(name, value);
    }

    @JsonAnyGetter
    public Map<String, AdobeResponseFinal> getAdobeResponseWrapper() {
        return adobeResponseWrapper;
    }
}

AdobeResponseFinal.class

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AdobeResponseFinal {
    public String entityId;
    public MergePolicy mergePolicy;
}

我这样调用服务:

final ResponseEntity<AdobeResponseDto> finalResponse;
finalResponse = aepClient.exchange(uri,HttpMethod.GET,entity,AdobeResponseDto.class);
final AdobeResponseDto body = finalResponse.getBody();

if(ObjectUtils.isNotEmpty(body)){
    return body;
}

但是这样一来,我得到的响应是

   {
    "adobeResponseWrapper": {
    "GvyArEFkg6JX6wI": {
        "entityId": "GvyArEFkg6JX6wI",
        "mergePolicy": {
            "id": "9245a39d-fe1a-4b33-acab-9bc5cbabf37c"
        }
     }

【问题讨论】:

    标签: java json spring-boot jackson


    【解决方案1】:

    如果您只想获取动态字段名称的值(例如,在您的情况下为“GvyArEFkg6JX6wI”),您可以将响应正文反序列化为Map,然后按如下方式遍历其值:

    ResponseEntity<String> finalResponse = aepClient.exchange(uri, HttpMethod.GET, entity, String.class);
    
    ObjectMapper objectMapper = new ObjectMapper();
    Map<String, Object> result = objectMapper.readValue(finalResponse.getBody(), Map.class);
    result.values().forEach(System.out::println);
    

    控制台输出:

    {entityId=GvyArEFkg6JX6wI, mergePolicy={id=9245a39d-fe1a-4b33-acab-9bc5cbabf37c}}


    如果您想将响应正文反序列化为您的 DTO(我假设只有 ONE 根级属性),您可以修改 DTO,如下所示:

    public class AdobeResponseDto {
        private AdobeResponseFinal adobeResponseFinal;
    
        @JsonAnySetter
        public void setAdobeResponseFinal(String name, AdobeResponseFinal value) {
            adobeResponseFinal = value;
        }
    
        @JsonAnyGetter
        public AdobeResponseFinal getAdobeResponseFinal() {
            return adobeResponseFinal;
        }
    }
    

    然后你可以得到类似的结果如下:

    ResponseEntity<String> finalResponse = aepClient.exchange(uri, HttpMethod.GET, entity, String.class);
    AdobeResponseDto adobeResponseDto = objectMapper.readValue(finalResponse.getBody(), AdobeResponseDto.class);
    System.out.println(adobeResponseDto.getAdobeResponseFinal().toString());
    

    控制台输出:

    AdobeResponseFinal{entityId='GvyArEFkg6JX6wI', mergePolicy=MergePolicy{id='9245a39d-fe1a-4b33-acab-9bc5cbabf37c'}}

    【讨论】:

    • 谢谢,我采用了第二种方法,但我有点失去了结构,我得到的正是你写的,所以响应中缺少动态属性{ "GvyArEFkg6JX6wI": {......}}我想保持原始响应不变。
    • 没问题!但是不知道你为什么还要保留原来的回复?
    猜你喜欢
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多