2017-01-27 43 views
1

我正在处理一个项目,在该项目中我将与返回JSON响应的第三方服务进行集成。我正在使用Jackson将反应序列化为Java POJO。答案是一个有几个简单字段的对象,Jackson可以轻松解析。但是,响应也包含一个数组,其中也包含一个对象。当Jackson试图反序列化它时,我得到包含列表中单个条目的列表的顶级对象,但列表中单个条目的所有字段均为空。任何想法我在这里做错了吗?Jackson:使用对象数组解析对象

更新:设置FAIL_ON_UNKNOWN_PROPERTIES为真后,我得到以下堆栈跟踪。仍然不确定为什么数组中包含“RecurringDetail”对象存在问题。无法识别的字段“RecurringDetail”(com.adyen.www.models.RecurringDetail类),未标记为可忽略的(19个已知属性:“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](通过引用链:com.adyen.www.models.RecurringDetailsResult [“details”] - > java.util.ArrayList [0] - > com.adyen.www.models.RecurringDetail [ RecurringDetail“]) 在com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62) 在com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834) 在融为一体。 fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094) 在com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470) 在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) 在com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499) 在com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101) 在com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDese在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": "[email protected]", 
"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; 
} 

} 

模型(阵列中的物体,所有领域的当杰克逊反序列化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; 
} 

} 
+0

我试过这个UNWRAP_SINGLE_VALUE_ARRAYS设置为两个真假。我也尝试过将ACCEPT_SINGLE_VALUE_AS_ARRAY设置为true和false。 – Steve

+0

我已将DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES设置为true,现在正在获取此堆栈跟踪 – Steve

+0

您是否可以自由更改json?问题是你的外部对象没有一个根值,但是你的内部对象是这样做的。 – teacurran

回答

0

的我能想到的最简单的事情就是让你的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

+0

谢谢。将包装器对象添加到我的Java模型中就像一个魅力。 – Steve

0

看来当前的结构将为响应工作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": "[email protected]", 
"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; 
} 

}