2011-05-22 5 views
2

Я работаю над приложением Android, используя API EmpireAvenue. API использует JSON, и я использую библиотеку GSON для анализа данных из API. Вот проблема:Parse JSON без конкретной структуры для поля с GSON

У меня есть структура 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" 
} 

Как вы можете видеть, структура, связанная с информационным полем отличается. Иногда это объект, иногда массив. Как и ожидалось, библиотека GSON генерирует ошибки при разборе. Вы знаете, как разбирать структуру JSON при изменении структуры поля?

Благодарим за помощь.

ответ

1

Текущее решение с Gson немного связано с требованием реализации пользовательского создателя экземпляра и/или настраиваемого десериализатора. Взгляните на http://code.google.com/p/google-gson/issues/detail?id=231 и the release notes on Hierarchical Type Adapters. Я только что опубликовал пример полиморфной десериализации с Gson в ответ на Polymorphism with gson.

Gson hopefully скоро будет иметь 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<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(); 
    } 
} 
Смежные вопросы