Parse JSON with no specific structure for a field with GSON

后端 未结 1 895
天涯浪人
天涯浪人 2021-01-23 06:47

I am working on an Android application, using the EmpireAvenue API. The API uses JSON and I\'m using the GSON library to parse the data from the API. Here is the problem:

<
相关标签:
1条回答
  • 2021-01-23 07:08

    The current solution with Gson is a bit involved, requiring implementation of a custom Instance Creator and/or a custom Deserializer. 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. I just posted an example of polymorphic deserialization with Gson in response to Polymorphism with gson.

    Gson hopefully will soon have the RuntimeTypeAdapter for simpler polymorphic deserialization. See http://code.google.com/p/google-gson/issues/detail?id=231 for more info.

    On the other hand, a Jackson-based solution isn't so bad.

    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();
      }
    }
    
    0 讨论(0)
提交回复
热议问题