{
"page": 1,
"pages": 1,
"rows": [
{
"context": false,
"created": 1490782661,
"RUB": {
"currency": "RUB",
"created": 1490761924,
"rate_buy": 5.53,
"rate_sell": 5.57,
"context": false
},
"EUR": {
"currency": "EUR",
"created": 1490770163,
"rate_buy": 340,
"rate_sell": 342,
"context": false
},
"USD": {
"currency": "USD",
"created": 1490782661,
"rate_buy": 315.3,
"rate_sell": 316.1,
"context": false
}
},
{
"context": false,
"created": 1490779161,
"RUB": {
"currency": "RUB",
"created": 1490761924,
"rate_buy": 5.53,
"rate_sell": 5.57,
"context": false
},
"EUR": {
"currency": "EUR",
"created": 1490770163,
"rate_buy": 340,
"rate_sell": 342,
"context": false
},
"USD": {
"currency": "USD",
"created": 1490779161,
"rate_buy": 315.1,
"rate_sell": 315.9,
"context": false
}
},
{
"context": false,
"created": 1490772405,
"RUB": {
"currency": "RUB",
"created": 1490761924,
"rate_buy": 5.53,
"rate_sell": 5.57,
"context": false
},
"EUR": {
"currency": "EUR",
"created": 1490770163,
"rate_buy": 340,
"rate_sell": 342,
"context": false
},
"USD": {
"currency": "USD",
"created": 1490772405,
"rate_buy": 314.9,
"rate_sell": 315.7,
"context": false
}
}
],
"total": "132"
}
答案 0 :(得分:1)
不要总是信任自动副模式生成器,因为它们无法为非平凡的情况生成强大而有效的映射。因此,这里非常受欢迎的建议在线工具也不能产生良好的映射,因为至少:
int
或long
。Map
灵活性。首先,让我们定义映射:
final class Response<T> {
// Note a few things:
// - Gson can deserialize final fields, and these are incoming data supposed to be read-only
// - There are no getters for brevity, these are just incoming data bags anyway
// - If `final`, primitive types like `int` should not be initialized with `0` (javac inlines such constants)
// so we're cheating making them look like constants...
@SerializedName("page") final int page = Integer.valueOf(0);
@SerializedName("pages") final int pages = Integer.valueOf(0);
@SerializedName("rows") final List<T> rows = null;
@SerializedName("total") final int total = Integer.valueOf(0);
}
与前一个类不同,Rate
类无法使用Gson通常处于最佳状态的反射策略进行反序列化。该类有一个构造函数,所以我们可以自己实例化它:
final class Rate {
final boolean context;
final Date created;
final Map<String, Currency> currencies;
Rate(final boolean context, final Date created, final Map<String, Currency> currencies) {
this.context = context;
this.created = created;
this.currencies = currencies;
}
}
final class Currency {
@SerializedName("currency") final String currency = null;
@SerializedName("created") final Date created = null;
@SerializedName("rate_buy") final double rateBuy = Double.valueOf(0);
@SerializedName("rate_sell") final double rateSell = Double.valueOf(0);
@SerializedName("context") final boolean context = Boolean.valueOf(false);
}
接下来,需要两个反序列化器:日期和费率。
final class DateJsonDeserializer
implements JsonDeserializer<Date> {
// No state? So it can be a singleton
private static final JsonDeserializer<Date> dateJsonDeserializer = new DateJsonDeserializer();
private DateJsonDeserializer() {
}
// But not letting client code know if it's a singleton or not -- it's encapsulated
static JsonDeserializer<Date> getDateJsonDeserializer() {
return dateJsonDeserializer;
}
@Override
public Date deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
// jsonElement.getAsLong() would work either
// But even longs can have their own deserialization strategy
// Note `* 1000` -- `java.util.Date` accepts milliseconds while Unix epoch is "seconds-based"
return new Date((Long) context.deserialize(jsonElement, long.class) * 1000);
}
}
final class RateJsonDeserializer
implements JsonDeserializer<Rate> {
private static final JsonDeserializer<Rate> rateJsonDeserializer = new RateJsonDeserializer();
private RateJsonDeserializer() {
}
static JsonDeserializer<Rate> getRateJsonDeserializer() {
return rateJsonDeserializer;
}
@Override
public Rate deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
boolean rateContext = false;
Date rateCreated = null;
final Map<String, Currency> rateCurrencies = new LinkedHashMap<>();
// Analyzing rate JSON documents for each key/value pair
for ( final Entry<String, JsonElement> entry : jsonObject.entrySet() ) {
final String key = entry.getKey();
final JsonElement value = entry.getValue();
switch ( key ) {
case "context":
rateContext = context.deserialize(value, boolean.class);
break;
case "created":
rateCreated = context.deserialize(value, Date.class);
break;
default:
rateCurrencies.put(key, context.deserialize(value, Currency.class));
break;
}
}
// So that we can "unwrap" its layout and "flatten" the currencies map
return new Rate(rateContext, rateCreated, rateCurrencies);
}
}
现在,它的使用方式:
private static final TypeToken<Response<Rate>> currencyRatesResponseTypeToken = new TypeToken<Response<Rate>>() {
};
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, getDateJsonDeserializer())
.registerTypeAdapter(Rate.class, getRateJsonDeserializer())
.create();
public static void main(final String... args) {
final Response<Rate> response = gson.fromJson(JSON, currencyRatesResponseTypeToken.getType());
System.out.println(response.page + "/" + response.pages + " (" + response.total + ")");
for ( final Rate rate : response.rows ) {
System.out.println(rate.created);
for ( final Entry<String, Currency> entry : rate.currencies.entrySet() ) {
final Currency currency = entry.getValue();
System.out.println("* " + entry.getKey() + " <== " + currency.currency + " (" + currency.rateBuy + "/" + currency.rateSell + ") " + currency.created);
}
}
}
演示输出:
1/1(132)
3月29日星期三13:17:41 EEST 2017年 * RUB&lt; == RUB(5.53 / 5.57)Wed Mar 29 07:32:04 EEST 2017
* EUR&lt; == EUR(340.0 / 342.0)3月29日星期三09:49:23 EEST 2017年 * USD&lt; == USD(315.3 / 316.1)Wed Mar 29 13:17:41 EEST 2017
3月29日星期三12:19:21 EEST 2017年 * RUB&lt; == RUB(5.53 / 5.57)Wed Mar 29 07:32:04 EEST 2017
* EUR&lt; == EUR(340.0 / 342.0)3月29日星期三09:49:23 EEST 2017年 * USD&lt; == USD(315.1 / 315.9)3月29日星期三12:19:21 EEST 2017
3月29日星期三10:26:45 EEST 2017年 * RUB&lt; == RUB(5.53 / 5.57)Wed Mar 29 07:32:04 EEST 2017
* EUR&lt; == EUR(340.0 / 342.0)3月29日星期三09:49:23 EEST 2017年 * USD&lt; == USD(314.9 / 315.7)3月29日星期三10:26:45 EEST 2017