对于具有GSON的字段,没有特定结构的Parse JSON

我正在使用EmpireAvenue API开发Android应用程序。 API使用JSON,我使用GSON库来解析API中的数据。 这是问题所在:

我有一个像这样的JSON结构:

{ type: "earnings", info: { earnings: 64.09 dividends: 1277.34 gains: 1997.05 expenses: 4895.51 shares_bought: 210 shares_bought_user_count: 2 shares_sold: 0 shares_sold_user_count: 0 }, created: "2011-04-16 11:32:37" }, { type: "following", info: [ { ticker: "SOLPHE" full_name: "Rodrigo Bermudez Salazar" list_name: "My Recommended Buys" }, { ticker: "SOLPHE" full_name: "Rodrigo Bermudez Salazar" list_name: "My Watch List" } ], created: "2011-04-16 11:00:08" } 

如您所见,与info字段关联的结构是不同的。 有时它是一个对象,有时是一个数组。 正如所料,GSON库在解析时会抛出错误。 你知道如何在字段改变结构时解析JSON结构吗?

谢谢你的帮助。

Gson当前的解决方案有点涉及,需要实现自定义实例创建器和/或自定义反序列化器。 有关详细信息,请查看http://code.google.com/p/google-gson/issues/detail?id=231以及有关分层类型适配器的发行说明 。 我刚刚用Gson发布了一个多态反序列化的例子,以响应gson的多态性 。

Gson希望很快就会有RuntimeTypeAdapter来实现更简单的多态反序列化。 有关详细信息,请参阅http://code.google.com/p/google-gson/issues/detail?id=231 。

另一方面,基于jackson的解决方案并不是那么糟糕。

 public class Foo { static String jsonInput = "[" + "{" + "\"type\":\"earnings\"," + "\"info\":" + "{" + "\"earnings\":64.09," + "\"dividends\":1277.34," + "\"gains\":1997.05," + "\"expenses\":4895.51," + "\"shares_bought\":210," + "\"shares_bought_user_count\":2," + "\"shares_sold\":0," + "\"shares_sold_user_count\":0" + "}," + "\"created\":\"2011-04-16 11:32:37\"" + "}," + "{" + "\"type\":\"following\"," + "\"info\":" + "[" + "{" + "\"ticker\":\"SOLPHE\"," + "\"full_name\":\"RodrigoBermudezSalazar\"," + "\"list_name\":\"MyRecommendedBuys\"" + "}," + "{" + "\"ticker\":\"SOLPHE\"," + "\"full_name\":\"RodrigoBermudezSalazar\"," + "\"list_name\":\"MyWatchList\"" + "}" + "]," + "\"created\":\"2011-04-16 11:00:08\"" + "}" + "]"; public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.setPropertyNamingStrategy(new CamelCaseNamingStrategy()); DateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); mapper.setDateFormat(dataFormat); Collection things = mapper.readValue(jsonInput, new TypeReference>(){}); System.out.println(things); } } @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type") @JsonSubTypes({@Type(value=Earnings.class, name="earnings"), @Type(value=Following.class, name="following")}) abstract class Thing { private Date created; void setCreated(Date created) { this.created = created; } @Override public String toString() { return String.format( "[%1$s: created=%2$s, other attributes:%3$s]", getClass().getSimpleName(), created, toStringAddenda()); } abstract String toStringAddenda(); } class Earnings extends Thing { private EarningsInfo info; void setInfo(EarningsInfo info) { this.info = info; } @Override String toStringAddenda() { return info.toString(); } } class Following extends Thing { private Collection info; void setInfo(Collection info) { this.info = info; } @Override String toStringAddenda() { return info.toString(); } } class FollowingInfo { private String ticker; private String fullName; private String listName; void setTicker(String ticker) { this.ticker = ticker; } void setFullName(String fullName) { this.fullName = fullName; } void setListName(String listName) { this.listName = listName; } @Override public String toString() { return String.format( "[FollowingInfo: ticker=%1$s, fullName=%2$s, listName=%3$s]", ticker, fullName, listName); } } class EarningsInfo { private BigDecimal earnings; private BigDecimal dividends; private BigDecimal gains; private BigDecimal expenses; private int sharesBought; private int sharesBoughtUserCount; private int sharesSold; private int sharesSoldUserCount; void setEarnings(BigDecimal earnings) { this.earnings = earnings; } void setDividends(BigDecimal dividends) { this.dividends = dividends; } void setGains(BigDecimal gains) { this.gains = gains; } void setExpenses(BigDecimal expenses) { this.expenses = expenses; } void setSharesBought(int sharesBought) { this.sharesBought = sharesBought; } void setSharesBoughtUserCount(int sharesBoughtUserCount) { this.sharesBoughtUserCount = sharesBoughtUserCount; } void setSharesSold(int sharesSold) { this.sharesSold = sharesSold; } void setSharesSoldUserCount(int sharesSoldUserCount) { this.sharesSoldUserCount = sharesSoldUserCount; } @Override public String toString() { return String.format( "[EarningsInfo: earnings=%1$s, dividends=%2$s, gains=%3$s, expenses=%4$s, sharesBought=%5$s, sharesBoughtUserCount=%6$s, sharesSold=%7$s, sharesSoldUserCount=%8$s]", earnings, dividends, gains, expenses, sharesBought, sharesBoughtUserCount, sharesSold, sharesSoldUserCount); } } class CamelCaseNamingStrategy extends PropertyNamingStrategy { @Override public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) { return convert(defaultName); } @Override public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) { return convert(defaultName); } @Override public String nameForField(MapperConfig config, AnnotatedField field, String defaultName) { return convert(defaultName); } private String convert(String defaultName) { char[] nameChars = defaultName.toCharArray(); StringBuilder nameTranslated = new StringBuilder(nameChars.length * 2); for (char c : nameChars) { if (Character.isUpperCase(c)) { nameTranslated.append("_"); c = Character.toLowerCase(c); } nameTranslated.append(c); } return nameTranslated.toString(); } }