栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何在Android中基于动态SerializedName用gson解析json对象

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何在Android中基于动态SerializedName用gson解析json对象

通过您提供的链接可访问的当前JSON响应似乎存在一些设计问题或怀疑。我将在此处发布JSON,以免将来丢失它:

{    "weather": {        "forecast3hours": [ {     "grid": {         "city": "충북",         "county": "충주시",         "village": "목행동",         "latitude": "37.0135600000",         "longitude": "127.9036500000"     },     "lightning1hour": "0",     "timeRelease": "2017-02-24 16:30:00",     "wind": {         "wspd2hour": "3.10",         "wdir1hour": "179.00",         "wspd1hour": "4.20",         "wdir2hour": "176.00",         "wdir3hour": "",         "wspd3hour": "",         "wdir4hour": "",         "wspd4hour": ""     },     "precipitation": {         "sinceOntime1hour": "0.00",         "type1hour": "0",         "sinceOntime2hour": "0.00",         "type2hour": "0",         "sinceOntime3hour": "",         "type3hour": "",         "sinceOntime4hour": "",         "type4hour": ""     },     "sky": {         "pre1hour": "SKY_V01",         "name1hour": "맑음",         "pre2hour": "SKY_V01",         "name2hour": "맑음",         "pre3hour": "",         "name3hour": "",         "pre4hour": "",         "name4hour": ""     },     "temperature": {         "temp1hour": "3.20",         "temp2hour": "2.00",         "temp3hour": "",         "temp4hour": ""     },     "humidity": {         "rh1hour": "41.00",         "rh2hour": "50.00",         "rh3hour": "",         "rh4hour": ""     },     "lightning2hour": "0",     "lightning3hour": "",     "lightning4hour": "" }        ]    },    "common": {        "alertYn": "N",        "stormYn": "N"    },    "result": {        "pre": 9200,        "requestUrl": "/weather/forecast/3hours?lon=127.9259&lat=36.991&version=1&appKey=4ce0462a-3884-30ab-ab13-93efb1bc171f",        "message": "성공"    }}

从我的角度来看,它们是:

  • 没有数组,而是人为索引的对象键(这是您的问题的主题)。
  • 空字符串表示可能的
    null
    值,而不是
    null
    s或仅将其排除在响应之外。
  • 几乎所有的值都表示为字符串文字,即使它们似乎是非字符串也是如此。
  • 布尔值似乎用
    Yn
    后缀标记,分别定义
    true
    false
    使用
    "Y"
    "N"

这就是为什么自动POJO生成器可能不是最佳的处理方式,因为它们可能无法检测到特定JSON字符串值的“真实”类型,而且它们无法生成自定义反序列化器。不知道为什么要这样设计,但是您可以设计自定义映射,使其对程序更加友好,并且可以对其进行更多控制。

final class Response {    final Weather weather = null;    final Common common = null;    final Result result = null;    @Override    public String toString() {        return new StringBuilder("Response{")     .append("weather=").append(weather)     .append(", common=").append(common)     .append(", result=").append(result)     .append('}').toString();    }}final class Weather {    final List<Forecast> forecast3hours = null;    @Override    public String toString() {        return new StringBuilder("Weather{")     .append("forecast3hours=").append(forecast3hours)     .append('}').toString();    }}final class Forecast {    final Grid grid;    final Date timeRelease;    final List<Integer> lightnings;    final List<Wind> winds;    final List<Precipitation> precipitations;    final List<Sky> skies;    final List<Float> temperatures;    final List<Float> humidities;    Forecast(final Grid grid, final Date timeRelease, final List<Integer> lightnings, final List<Wind> winds, final List<Precipitation> precipitations, final List<Sky> skies, final List<Float> temperatures, final List<Float> humidities) {        this.grid = grid;        this.timeRelease = timeRelease;        this.lightnings = lightnings;        this.winds = winds;        this.precipitations = precipitations;        this.skies = skies;        this.temperatures = temperatures;        this.humidities = humidities;    }    @Override    public String toString() {        return new StringBuilder("Forecast{")     .append("grid=").append(grid)     .append(", timeRelease=").append(timeRelease)     .append(", lightnings=").append(lightnings)     .append(", winds=").append(winds)     .append(", precipitations=").append(precipitations)     .append(", skies=").append(skies)     .append(", temperatures=").append(temperatures)     .append(", humidities=").append(humidities)     .append('}').toString();    }}final class Grid {    final String city = null;    final String county = null;    final String village = null;    final double latitude = Double.valueOf(0); // disable inlining the primitive double 0    final double longitude = Double.valueOf(0); // disable inlining the primitive double 0    @Override    public String toString() {        return new StringBuilder("Grid{")     .append("city='").append(city).append(''')     .append(", county='").append(county).append(''')     .append(", village='").append(village).append(''')     .append(", latitude=").append(latitude)     .append(", longitude=").append(longitude)     .append('}').toString();    }}final class Wind {    final float speed;    final float direction;    Wind(final float speed, final float direction) {        this.speed = speed;        this.direction = direction;    }    @Override    public String toString() {        return new StringBuilder("Wind{")     .append("speed=").append(speed)     .append(", direction=").append(direction)     .append('}').toString();    }}final class Precipitation {    final float sinceOntime;    final int type;    Precipitation(final float sinceOntime, final int type) {        this.sinceontime = sinceOntime;        this.type = type;    }    @Override    public String toString() {        return new StringBuilder("Precipitation{")     .append("sinceontime='").append(sinceOntime).append(''')     .append(", type=").append(type)     .append('}').toString();    }}final class Sky {    final String pre;    final String name;    Sky(final String pre, final String name) {        this.pre = pre;        this.name = name;    }    @Override    public String toString() {        return new StringBuilder("Sky{")     .append("pre='").append(pre).append(''')     .append(", name='").append(name).append(''')     .append('}').toString();    }}final class Common {    @SerializedName("alertYn")    @JsonAdapter(YnToBooleanJsonDeserializer.class)    final boolean alert = Boolean.valueOf(false); // disable inlining the primitive boolean false    @SerializedName("stormYn")    @JsonAdapter(YnToBooleanJsonDeserializer.class)    final boolean storm = Boolean.valueOf(false); // disable inlining the primitive boolean false    @Override    public String toString() {        return new StringBuilder("Common{")     .append("alert=").append(alert)     .append(", storm=").append(storm)     .append('}').toString();    }}final class Result {    final int pre = Integer.valueOf(0); // disable inlining the primitive int 0    final String requestUrl = null;    final String message = null;    @Override    public String toString() {        return new StringBuilder("Result{")     .append("pre=").append(pre)     .append(", requestUrl='").append(requestUrl).append(''')     .append(", message='").append(message).append(''')     .append('}').toString();    }}

其中一些映射具有显式构造函数-
必须在自定义反序列化器中手动实例化此类对象。如果没有提供构造函数,那么Gson可以处理这种映射本身,而该映射只具有有关应如何反序列化特定对象的足够信息。

由于应该以非标准方式解析数据,因此可以实现几个自定义反序列化器。以下类型适配器分别将

"Y"
和转换
"N"
true
false

final class YnToBooleanJsonDeserializer        implements JsonDeserializer<Boolean> {    // Gson will instantiate this adapter itself    private YnToBooleanJsonDeserializer() {    }    @Override    public Boolean deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) throws JsonParseException {        final String rawFlag = jsonElement.getAsString();        switch ( rawFlag ) {        case "N": return false;        case "Y": return true;        default: throw new JsonParseException("Can't parse: " + rawFlag);        }    }}

下一个

JsonDeserializer
尝试
xxx<N>hour
使用正则表达式检测类似键,并提取
<N>
索引以构建构造
Forecast
实例所需的列表。请注意,它可以解析任意大小的“列表”(JSON中的列表)。

final class ForecastJsonDeserializer        implements JsonDeserializer<Forecast> {    // This deserializer does not hold any state and can be instantiated once per application life-cycle.    private static final JsonDeserializer<Forecast> forecastJsonDeserializer = new ForecastJsonDeserializer();    private ForecastJsonDeserializer() {    }    static JsonDeserializer<Forecast> getForecastJsonDeserializer() {        return forecastJsonDeserializer;    }    @Override    public Forecast deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) throws JsonParseException {        final JsonObject jsonObject = jsonElement.getAsJsonObject();        return new Forecast(     context.deserialize(jsonObject.get("grid"), Grid.class),     context.deserialize(jsonObject.get("timeRelease"), Date.class),     lightningsExtractor.parseList(jsonObject),     windsExtractor.parseList(jsonObject.get("wind").getAsJsonObject()),     precipitationsExtractor.parseList(jsonObject.get("precipitation").getAsJsonObject()),     skiesExtractor.parseList(jsonObject.get("sky").getAsJsonObject()),     temperaturesExtractor.parseList(jsonObject.get("temperature").getAsJsonObject()),     humiditiesExtractor.parseList(jsonObject.get("humidity").getAsJsonObject())        );    }    private static final AbstractExtractor<Integer> lightningsExtractor = new AbstractExtractor<Integer>(compile("lightning(\d)hour")) {        @Override        protected Integer parse(final int index, final JsonObject jsonObject) { final String rawLightning = jsonObject.get("lightning" + index + "hour").getAsString(); if ( rawLightning.isEmpty() ) {     return null; } return parseInt(rawLightning);        }    };    private static final AbstractExtractor<Wind> windsExtractor = new AbstractExtractor<Wind>(compile("(?:wdir|wspd)(\d)hour")) {        @Override        protected Wind parse(final int index, final JsonObject jsonObject) { String rawSpeed = jsonObject.get("wspd" + index + "hour").getAsString(); String rawDirection = jsonObject.get("wdir" + index + "hour").getAsString(); if ( rawSpeed.isEmpty() && rawDirection.isEmpty() ) {     return null; } return new Wind(parseFloat(rawSpeed), parseFloat(rawDirection));        }    };    private static final AbstractExtractor<Precipitation> precipitationsExtractor = new AbstractExtractor<Precipitation>(compile("(?:sinceontime|type)(\d)hour")) {        @Override        protected Precipitation parse(final int index, final JsonObject jsonObject) { final String rawSinceontime = jsonObject.get("sinceOntime" + index + "hour").getAsString(); final String rawType = jsonObject.get("type" + index + "hour").getAsString(); if ( rawSinceOntime.isEmpty() && rawType.isEmpty() ) {     return null; } return new Precipitation(parseFloat(rawSinceOntime), parseInt(rawType));        }    };    private static final AbstractExtractor<Sky> skiesExtractor = new AbstractExtractor<Sky>(compile("(?:pre|name)(\d)hour")) {        @Override        protected Sky parse(final int index, final JsonObject jsonObject) { final String rawCode = jsonObject.get("pre" + index + "hour").getAsString(); final String rawName = jsonObject.get("name" + index + "hour").getAsString(); if ( rawCode.isEmpty() && rawName.isEmpty() ) {     return null; } return new Sky(rawCode, rawName);        }    };    private static final AbstractExtractor<Float> temperaturesExtractor = new AbstractExtractor<Float>(compile("temp(\d)hour")) {        @Override        protected Float parse(final int index, final JsonObject jsonObject) { final String rawTemperature = jsonObject.get("temp" + index + "hour").getAsString(); if ( rawTemperature.isEmpty() ) {     return null; } return parseFloat(rawTemperature);        }    };    private static final AbstractExtractor<Float> humiditiesExtractor = new AbstractExtractor<Float>(compile("rh(\d)hour")) {        @Override        protected Float parse(final int index, final JsonObject jsonObject) { final String rawHumidity = jsonObject.get("rh" + index + "hour").getAsString(); if ( rawHumidity.isEmpty() ) {     return null; } return parseFloat(rawHumidity);        }    };    private abstract static class AbstractExtractor<T> {        private final Pattern pattern;        private AbstractExtractor(final Pattern pattern) { this.pattern = pattern;        }        protected abstract T parse(int index, JsonObject jsonObject);        private List<T> parseList(final JsonObject jsonObject) { final List<T> list = new ArrayList<>(); for ( final Entry<String, JsonElement> e : jsonObject.entrySet() ) {     final String key = e.getKey();     final Matcher matcher = pattern.matcher(key);     // Check if the given regular expression matches the key     if ( matcher.matches() ) {         // If yes, then just extract and parse the index          final int index = parseInt(matcher.group(1));         // And check if there is enough room in the result list because the JSON response may contain unordered keys         while ( index > list.size() ) {  list.add(null);         }         // As Java lists are 0-based         if ( list.get(index - 1) == null ) {  // Assuming that null marks an object that's probably not parsed yet  list.set(index - 1, parse(index, jsonObject));         }     } } return list;        }    }}

现在可以将它们放在一起:

public static void main(final String... args) {    final Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd hh:mm:ss") .registerTypeAdapter(Forecast.class, getForecastJsonDeserializer()) .create();    final Response response = gson.fromJson(JSON, Response.class);    System.out.println(response);}

输出:

响应{天气=天气{forecast3hours = [预测{grid = Grid {city =’충북’,县=’충주시’,村庄=’목행동’,纬度=
37.01356,经度= 127.90365}},timeRelease =周五2月24日30:30 :00 EET 2017,闪电=
[0,0,null,null],风= [风{speed = 4.2,方向= 179.0},风{speed = 3.1,方向=
176.0},null,null],降水量= [降水{sinceontime =‘0.0’,类型= 0},降水{sinceOntime
=‘0.0’,类型= 0},null,null],天空= [Sky {pre =’SKY_V01’,name =’맑음’},Sky {pre
=’SKY_V01’,name =’맑음’},null,null],温度= [3.2,2.0,null,null],湿度=
[41.0,50.0,null,null]}]},common = Common { alert = false,storm =
false},result = Result {pre = 9200,requestUrl =’/ weather / forecast /
3hours?lon = 127.9259&lat = 36.991&version = 1&appKey = 4ce0462a-3884-30ab-
ab13-93efb1bc171f’,message =’성공’}}



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/516221.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号