简体   繁体   English

使用GSON解析没有特定结构的JSON字段

[英]Parse JSON with no specific structure for a field with GSON

I am working on an Android application, using the EmpireAvenue API. 我正在使用EmpireAvenue API开发一个Android应用程序。 The API uses JSON and I'm using the GSON library to parse the data from the API. 该API使用JSON,而我正在使用GSON库来解析该API中的数据。 Here is the problem: 这是问题所在:

I have a JSON structure like this: 我有一个像这样的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"
}

As you can see, the structure associated with the info field is different. 如您所见,与信息字段关联的结构是不同的。 Sometimes it's an object, sometimes an array. 有时是对象,有时是数组。 As expected, the GSON library throws errors when parsing. 不出所料,GSON库在解析时会引发错误。 Do you know how to parse a JSON structure with when a field changes structure ? 您知道当字段更改结构时如何解析JSON结构吗?

Thanks for your help. 谢谢你的帮助。

The current solution with Gson is a bit involved, requiring implementation of a custom Instance Creator and/or a custom Deserializer. 使用Gson的当前解决方案有些复杂,需要实现自定义实例创建器和/或自定义反序列化器。 Take a look at http://code.google.com/p/google-gson/issues/detail?id=231 and the release notes on Hierarchical Type Adapters for details. 有关详细信息,请参阅http://code.google.com/p/google-gson/issues/detail?id=231“分层类型适配器”上的发行说明 I just posted an example of polymorphic deserialization with Gson in response to Polymorphism with gson . 我刚刚发布了一个示例,该示例使用Gson多态反序列化来响应gson的多态性

Gson hopefully will soon have the RuntimeTypeAdapter for simpler polymorphic deserialization. 希望Gson不久将拥有RuntimeTypeAdapter以实现更简单的多态反序列化。 See http://code.google.com/p/google-gson/issues/detail?id=231 for more info. 有关更多信息,请参见http://code.google.com/p/google-gson/issues/detail?id=231

On the other hand, a Jackson -based solution isn't so bad. 另一方面,基于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<Thing> things = mapper.readValue(jsonInput, new TypeReference<Collection<Thing>>(){});
    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<FollowingInfo> info;

  void setInfo(Collection<FollowingInfo> 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();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM