当前位置: 首页 > 知识库问答 >
问题:

Jackson:使用对象数组分析对象

陈坚
2023-03-14

我正在做一个项目,我正在与返回JSON响应的第三方服务集成。我正在使用Jackson将响应反序列化为JavaPOJO。响应是一个对象,它有几个Jackson能够轻松解析的简单字段。但是响应还包含一个带有单个条目的数组,该条目也是一个对象。当Jackson尝试反序列化它时,我得到了包含列表中单个条目的顶级对象,但是列表中单个条目的所有字段都是空的。知道我在这里做错了什么吗?

更新:将FAIL\u ON\u UNKNOWN\u PROPERTIES设置为true后,我将获得以下堆栈跟踪。仍然不确定为什么数组中包装的“RecurringDetail”对象会出现问题。

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "RecurringDetail" (class com.adyen.www.models.RecurringDetail), not marked as ignorable (19 known properties: "variant", "contractTypes", "tokenDetails", "aliasType", "name", "creationDate", "firstPspReference", "elv", "card", "additionalData", "shopperName", "socialSecurityNumber", "billingAddress", "bank", "recurringDetailReference", "paymentMethodVariant", "alias", "acquirer", "acquirerAccount"])
 at [Source: response.json; line: 5, column: 33] (through reference chain: com.adyen.www.models.RecurringDetailsResult["details"]->java.util.ArrayList[0]->com.adyen.www.models.RecurringDetail["RecurringDetail"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1448)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:287)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2759)

JSON

{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
    {
        "RecurringDetail": {
            "acquirer": "TestPmmAcquirer",
            "acquirerAccount": "TestPmmAcquirerAccount",
            "additionalData": {
                "cardBin": "440000"
            },
            "alias": "B133243153928547",
            "aliasType": "Default",
            "card": {
                "expiryMonth": "8",
                "expiryYear": "2018",
                "holderName": "Steve HAll",
                "number": "0008"
            },
            "contractTypes": [
                "RECURRING"
            ],
            "creationDate": "2017-01-26T23:11:20+01:00",
            "firstPspReference": "8524854686798738",
            "paymentMethodVariant": "visadebit",
            "recurringDetailReference": "8414854686802111",
            "variant": "visa"
        }
    }
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones@email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}

单元测试

public class RecurringDetailResultTest {

public static ObjectMapper mapper = new ObjectMapper()
{
    private static final long serialVersionUID = -174113593500315394L;
    {
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true);
        setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }
};

@Test
public void testParseRecurringDetailResulte() throws IOException {

    RecurringDetailsResult result = mapper.readValue(new File("response.json"), new TypeReference<RecurringDetailsResult>(){});
    if (result.getDetails() != null && !result.getDetails().isEmpty()) {
        RecurringDetail detail = result.getDetails().get(0);
        if (StringUtils.isEmpty(detail.getRecurringDetailReference())) {
            fail("Recurring detail does not contain any information.");
        }
    } else {
        fail("No result details returned.");
    }

}

}

模型(根对象)

public class RecurringDetailsResult 
    implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<RecurringDetail> details;
private String lastKnownShopperEmail;

@JsonGetter("creationDate")
public Date getCreationDate ( ) { 
    return this.creationDate;
}

@JsonSetter("creationDate")
public void setCreationDate (Date value) { 
    this.creationDate = value;
}

@JsonGetter("shopperReference")
public String getShopperReference ( ) { 
    return this.shopperReference;
}

@JsonSetter("shopperReference")
public void setShopperReference (String value) { 
    this.shopperReference = value;
}

@JsonGetter("details")
public List<RecurringDetail> getDetails ( ) { 
    return this.details;
}

@JsonSetter("details")
public void setDetails (List<RecurringDetail> value) { 
    this.details = value;
}

@JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) { 
    return this.lastKnownShopperEmail;
}

@JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) { 
    this.lastKnownShopperEmail = value;
}

}

Model(数组中的对象,当Jackson反序列化JSON时,这家伙的所有字段都为空)

public class RecurringDetail 
    implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private ELV elv;
private Address billingAddress;
private String additionalData;
private Name shopperName;
private String socialSecurityNumber;
private String recurringDetailReference;
private BankAccount bank;
private String alias;
private String aliasType;
private TokenDetails tokenDetails;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;

@JsonGetter("name")
public String getName ( ) { 
    return this.name;
}

@JsonSetter("name")
public void setName (String value) { 
    this.name = value;
}

@JsonGetter("creationDate")
public Date getCreationDate ( ) { 
    return this.creationDate;
}

@JsonSetter("creationDate")
public void setCreationDate (Date value) { 
    this.creationDate = value;
}

@JsonGetter("card")
public Card getCard ( ) { 
    return this.card;
}

@JsonSetter("card")
public void setCard (Card value) { 
    this.card = value;
}

@JsonGetter("elv")
public ELV getElv ( ) { 
    return this.elv;
}

@JsonSetter("elv")
public void setElv (ELV value) { 
    this.elv = value;
}

@JsonGetter("billingAddress")
public Address getBillingAddress ( ) { 
    return this.billingAddress;
}

@JsonSetter("billingAddress")
public void setBillingAddress (Address value) { 
    this.billingAddress = value;
}

@JsonGetter("additionalData")
public String getAdditionalData ( ) { 
    return this.additionalData;
}

@JsonSetter("additionalData")
public void setAdditionalData (String value) { 
    this.additionalData = value;
}

@JsonGetter("shopperName")
public Name getShopperName ( ) { 
    return this.shopperName;
}

@JsonSetter("shopperName")
public void setShopperName (Name value) { 
    this.shopperName = value;
}

@JsonGetter("socialSecurityNumber")
public String getSocialSecurityNumber ( ) { 
    return this.socialSecurityNumber;
}

@JsonSetter("socialSecurityNumber")
public void setSocialSecurityNumber (String value) { 
    this.socialSecurityNumber = value;
}

@JsonGetter("recurringDetailReference")
public String getRecurringDetailReference ( ) { 
    return this.recurringDetailReference;
}

@JsonSetter("recurringDetailReference")
public void setRecurringDetailReference (String value) { 
    this.recurringDetailReference = value;
}

@JsonGetter("bank")
public BankAccount getBank ( ) { 
    return this.bank;
}

@JsonSetter("bank")
public void setBank (BankAccount value) { 
    this.bank = value;
}

@JsonGetter("alias")
public String getAlias ( ) { 
    return this.alias;
}

@JsonSetter("alias")
public void setAlias (String value) { 
    this.alias = value;
}

@JsonGetter("aliasType")
public String getAliasType ( ) { 
    return this.aliasType;
}

@JsonSetter("aliasType")
public void setAliasType (String value) { 
    this.aliasType = value;
}

@JsonGetter("tokenDetails")
public TokenDetails getTokenDetails ( ) { 
    return this.tokenDetails;
}

@JsonSetter("tokenDetails")
public void setTokenDetails (TokenDetails value) { 
    this.tokenDetails = value;
}

@JsonGetter("variant")
public String getVariant ( ) { 
    return this.variant;
}

@JsonSetter("variant")
public void setVariant (String value) { 
    this.variant = value;
}

@JsonGetter("paymentMethodVariant")
public String getPaymentMethodVariant ( ) { 
    return this.paymentMethodVariant;
}

@JsonSetter("paymentMethodVariant")
public void setPaymentMethodVariant (String value) { 
    this.paymentMethodVariant = value;
}

@JsonGetter("firstPspReference")
public String getFirstPspReference ( ) { 
    return this.firstPspReference;
}

@JsonSetter("firstPspReference")
public void setFirstPspReference (String value) { 
    this.firstPspReference = value;
}

@JsonGetter("contractTypes")
public List<String> getContractTypes ( ) { 
    return this.contractTypes;
}

@JsonSetter("contractTypes")
public void setContractTypes (List<String> value) { 
    this.contractTypes = value;
}

@JsonGetter("acquirer")
public String getAcquirer ( ) { 
    return this.acquirer;
}

@JsonSetter("acquirer")
public void setAcquirer (String value) { 
    this.acquirer = value;
}

@JsonGetter("acquirerAccount")
public String getAcquirerAccount ( ) { 
    return this.acquirerAccount;
}

@JsonSetter("acquirerAccount")
public void setAcquirerAccount (String value) { 
    this.acquirerAccount = value;
}

}

共有2个答案

梁丘霖
2023-03-14

似乎您当前的结构将适用于如下响应JSON(删除了一个额外的命名层)

{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
     {
            "acquirer": "TestPmmAcquirer",
            "acquirerAccount": "TestPmmAcquirerAccount",
            "additionalData": {
                "cardBin": "440000"
            },
            "alias": "B133243153928547",
            "aliasType": "Default",
            "card": {
                "expiryMonth": "8",
                "expiryYear": "2018",
                "holderName": "Steve HAll",
                "number": "0008"
            },
            "contractTypes": [
                "RECURRING"
            ],
            "creationDate": "2017-01-26T23:11:20+01:00",
            "firstPspReference": "8524854686798738",
            "paymentMethodVariant": "visadebit",
            "recurringDetailReference": "8414854686802111",
            "variant": "visa"
        }
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones@email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}

对于命名对象,您可以尝试以下操作

public class RecurringDetailsResult 
    implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<Map<String,RecurringDetail>> details;
private String lastKnownShopperEmail;

@JsonGetter("creationDate")
public Date getCreationDate ( ) { 
    return this.creationDate;
}

@JsonSetter("creationDate")
public void setCreationDate (Date value) { 
    this.creationDate = value;
}

@JsonGetter("shopperReference")
public String getShopperReference ( ) { 
    return this.shopperReference;
}

@JsonSetter("shopperReference")
public void setShopperReference (String value) { 
    this.shopperReference = value;
}

@JsonGetter("details")
public List<Map<String, RecurringDetail>> getDetails ( ) { 
    return this.details;
}

@JsonSetter("details")
public void setDetails (List<Map<String, RecurringDetail>> value) { 
    this.details = value;
}

@JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) { 
    return this.lastKnownShopperEmail;
}

@JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) { 
    this.lastKnownShopperEmail = value;
}

}
贺子昂
2023-03-14

我认为最简单的事情就是让java对象看起来像Json。因为这个Json有一个包装好的内部对象,而不是外部对象,所以在java中必须有一个类似的包装。它不雅致,但很管用。

public class RecurringDetailsResult implements java.io.Serializable {

    private Date creationDate;
    private String shopperReference;
    private List<RecurringDetailWrapper> details;
    private String lastKnownShopperEmail;

    // getters and setters here. No need for any @JsonGetter or @JsonSetter annotations
}


@JsonRootName("RecurringDetail")
public class RecurringDetailWrapper {

    @JsonProperty("RecurringDetail")
    RecurringDetail recurringDetail;

    public RecurringDetail getRecurringDetail() {
        return recurringDetail;
    }

    public void setRecurringDetail(RecurringDetail recurringDetail) {
        this.recurringDetail = recurringDetail;
    }
}


public class RecurringDetail implements java.io.Serializable {
    private static final long serialVersionUID = 5302883242997268343L;

    private String name;
    private Date creationDate;
    private Card card;
    private AdditionalData additionalData;
    private String socialSecurityNumber;
    private String recurringDetailReference;
    private String alias;
    private String aliasType;
    private String variant;
    private String paymentMethodVariant;
    private String firstPspReference;
    private List<String> contractTypes;
    private String acquirer;
    private String acquirerAccount;

    public class AdditionalData {
        String cardBin;

        public String getCardBin() {
            return cardBin;
        }

        public void setCardBin(String cardBin) {
            this.cardBin = cardBin;
        }
    }

    // getters and setters here. No need for any @JsonGetter or @JsonSetter annotations

} 

然后在单元测试中:

@Test
public void testParseRecurringDetailResulte() throws IOException {

    InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("ID41901838.json");

    ObjectReader objectReader = mapper.readerFor(RecurringDetailsResult.class);
    RecurringDetailsResult result = objectReader.readValue(inputStream);

    if (result.getDetails() != null && !result.getDetails().isEmpty()) {
        RecurringDetailWrapper detail = result.getDetails().get(0);
        if (StringUtils.isEmpty(detail.getRecurringDetail().getRecurringDetailReference())) {
            fail("Recurring detail does not contain any information.");
        }
    } else {
        fail("No result details returned.");
    }
}

我在这里发布了完整的工作代码:https://github.com/teacurran/java-experiments/tree/master/stackoverflow-sandbox/src/main/java/com/wirelust/stackoverflowsandbox/ID41901838

 类似资料:
  • 我遇到需要解析不相同的 JSON 对象数组的情况。 所以例如: 类型的数量是有限的,可以很好地定义每种类型的内容,但无法定义将保存内容的单一类型的对象。 有没有办法用杰克逊来解析它们? 附言。如果可以的话,我试图避免编写自定义解析器。

  • 我正在将Jackson从1.9.4升级到2.2.0。过渡非常顺利,只是我似乎无法对对象进行数组解析。在1.9.4中,我可以这样做: 在Jackson 2.2.0中,我得到了一个“无法解析方法”编译时错误。Jackson 1.9.4的ObjectMapper头文件包含以下JsonNodes的readValue方法: 和Jackson 2.2.0的头文件: 所以我需要从传递JsonNode切换到Jso

  • 问题内容: 我有一个包含对象的json数组的文件: [{“ test1”:“ abc”},{“ test2”:[1,2,3]}] 我希望使用Jackson的JsonParser来从此文件中获取输入流,并且在每次调用.next()时,我希望它从数组中返回一个对象,直到用完对象或失败为止。 这可能吗? 用例:我有一个带有json数组的大文件,其中填充有大量具有不同架构的对象。我想一次获得一个对象,以避

  • 我的数组是这样的: 我想把这个转换成: 所以,基本上,按分组。 我正在尝试: 我只是不知道如何处理相似组值的分组。

  • 问题内容: 我的数组是这样的: 我想将其转换为: 因此,基本上,分组依据。 我尝试着: 我只是不知道如何处理相似组值的分组。 问题答案: 首先,在JavaScript中,使用遍历数组通常不是一个好主意。 因此,您可以尝试执行以下操作: 在这里使用中间对象有助于加快处理速度,因为它可以避免嵌套循环搜索数组。另外,因为使用迭代遍历对象(而不是数组)是合适的。 附录 FWIW,如果要避免在结果数组中出现

  • 我有一个任务解析Json到Java类。 我试图解析的Json片段有点像树结构。 这里的关键点是,参数值可以是字符串,也可以是参数名称/值对的另一个数组; 我想用杰克逊地图绘制器 这里的问题是我不知道如何在这里描述响应类,所以它可以被杰克逊自动解析。如果有可能的话。 Json: