前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >魔改 TypeAdapterFactory

魔改 TypeAdapterFactory

作者头像
HelloVass
发布于 2018-09-12 02:25:14
发布于 2018-09-12 02:25:14
2K00
代码可运行
举报
文章被收录于专栏:Hellovass 的博客Hellovass 的博客
运行总次数:0
代码可运行

前言

感慨:Retrofit2 虽好,但是,有时候总感觉 Java 这门语言还是美中不足啊!

恼人的问题

想象一下,有这么几个 Api:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

// 获取手机验证码
@POST("/user/sms") Observable<ServerResult<SmsCode>> fetchSmsCode(@Body PhoneNum phoneNum);

// 获取 AuthCode
@POST("/authcode") Observable<ServerResult<AuthCode>> fetchAuthCode(@Body SmsCodeAndOtherParams smsCodeAndOtherParams)

为什么很烦呢?

需要起名字

因为需要用 Gson 解析来解析 json,所以我们需要按照 server 返回的 json 来定义我们的请求体(被 @Body 注解的参数)以及响应体。然而,我这人最烦的就是命名了,本来词汇量就匮乏,还要想名字?

需要新建 class

上面两个 Api,我们需要定义 SmsCode、PhoneNum、AuthCode、SmsCodeAndOtherParams 四个类,然后在类里按照 json 的 key 定义对应的成员变量。

调用 Api 的时候,代码好脏啊

我们需要 new 参数,举栗:调用 fetchSmsCode 前,我们需要 new PhoneNum() 并且给它的成员变量赋值,当然如果我们是爱干净的好孩子的话可能会用 Builder 模式来做,但是谁来写这么多的 builder 呢?这可是体力活啊

解决方案

问个问题,如果是 JS 的话,这段代码该怎么写呢?

我想,大概是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var smsCode = etchSmsCode({"phoneNumber":"159XXXXXXXX"})

哇,真爽,不用新建 class,不用费力想名字,毕竟我们做 POST 请求的时候,只是想 POST 一个匿名的 JsonObject 而已,新建 class 什么的,真的没必要。

理想的 Api
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

/**
    * 获取验证码
    */
   @POST("/user/sms") Observable<Response<ServerResult<Params>>> fetchSmsCode(
       @Body Params params);

   /**
    * 获取 AuthCode
    */
   @POST("/authcode") Observable<Response<ServerResult<Params>>> fetchAuthCode(
       @Body Params params);
期望的调用
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

// 获取验证码
PeroRetrofitWrapperStore.getInstance()
        .provideApi(PeroApi.UserApi.class)
        .fetchSmsCode(new Params.Builder().put("phoneNumber", phoneNum).create())
        // ... 省略若干代码

虽然没有 JS 那么简洁,但是看起来已经没有那么恼人了。那么问题来了,该怎么魔改,实现这样的愿望呢?

利用 TypeAdapterFactory 这个接口

如果对我上篇文章有印象的小伙伴可能会留意下这段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

@Override public Converter.Factory createGsonConverterFactory() {

    Gson gson =
        new GsonBuilder().registerTypeAdapterFactory(provideParamsAdapterFactory()).create();

    return GsonConverterFactory.create(gson);
  }

这段代码里,我创建了一个 ParamsAdapterFactory (继承自 TypeAdapterFactory),并注册到了 GsonBuilder 中。那这有什么用呢?其实非常有用,TypeAdapterFactory 内部会创建一个 ParamsAdapter,接管了 json 的序列化和反序列化!

来看看我们的 ParamsAdapter 做了什么?代码不长,挑重要的分析下。因为我们接管了 json 的序列化过程,在执行 POST 请求的时候,fetchSmsCode(@Body parmas) 方法里接受的 params 参数就会走这段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

   @Override public void write(JsonWriter jsonWriter, Params params) throws IOException {

     if (params == null) {

       jsonWriter.nullValue();
       return;
     }

     jsonWriter.beginObject();

     Map<String, String> map = params.getExtrasMap();

     for (String key : map.keySet()) {

       jsonWriter.name(key);
       jsonWriter.value(map.get(key));
     }

     jsonWriter.endObject();
}

其实也就是序列化过程,最后 params 会转换成我们想要的 {"phoneNumber":"159XXXXXXX"} json 格式 ,接下来的事情就交给 Retrofit(像往常一样)。

同理可得,反序列化过程,就是将服务器返回的 json 解析为,我们期望的 params,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

@Override public Params read(JsonReader jsonReader) throws IOException {

      if (jsonReader.peek() == JsonToken.NULL) {

        jsonReader.nextNull();
        return null;
      }

      Params.Builder builder = new Params.Builder();

      jsonReader.beginObject();

      while (jsonReader.hasNext()) {

        String key = jsonReader.nextName();
        String value = jsonReader.nextString();

        builder.put(key, value);
      }

      jsonReader.endObject();

      return builder.create();
    }

反序列化完毕之后,我们就可以从 params 里拿到自己想要的值,例如:String authCode = params.get("authCode"),这里的 Params 就相当于一个 Map,事实上它内部确实是用一个 Map<String,String> 来存取键值对的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

public final class Params {

  private Map<String, String> mExtrasMap;

  private Params(Builder builder) {

    mExtrasMap = builder.mExtrasMap;
  }

  public String get(String key) {

    return mExtrasMap.get(key);
  }

  public Map<String, String> getExtrasMap() {

    return mExtrasMap;
  }

  @Override public String toString() {

    return "Params{" + "mExtrasMap=" + mExtrasMap + '}';
  }

  public static class Builder {

    private Map<String, String> mExtrasMap;

    public Builder() {

      mExtrasMap = new HashMap<>();
    }

    public Builder put(String key, String value) {

      mExtrasMap.put(key, value);
      return this;
    }

    public Params create() {

      return new Params(this);
    }
  }
}

代码灰常简单,对不对?到这里,魔改原理就差不多解释清楚了。

当然,可能会有人质疑,那 up 你的意思是劳资不用自己费力写 POJO,全用你的 Params 来替代?(如果我回答不是,你会不会一棒子打过来?)

使用场景

这个,我一开始也没提。如果到了不是非常有必要定义 POJO 的时候,比如,你只是想要 POST 一个 phoneNumber 或者 authCode 的时候,真的没必要为此定义 POJO,多累呢!遇到这种情况,能创建一个匿名的 params 就创建呗,省下来的时间还能陪陪学妹,何乐而不为!

也有童鞋会说,老板,你把序列化和反序列化全部接管了,如果我没有用你的 Params ,会不会解析异常?(这点我肯定考虑到了好吧,不然菊花肯定都没了)

类型检查

这里我们判断 rawType,如果是 Params 的话,就返回我们的 ParamsAdaper,否则返回 null,表示不支持。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {

    Class<T> rawType = (Class<T>) typeToken.getRawType();

    if (Params.class.isAssignableFrom(rawType)) {

      return (TypeAdapter<T>) new ParamsAdapter();
    }

    return null;
  }
完整的 TypeAdapterFactory 代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

public final class ParamsAdapterFactory
    implements TypeAdapterFactory {

  @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {

    Class<T> rawType = (Class<T>) typeToken.getRawType();

    if (Params.class.isAssignableFrom(rawType)) {

      return (TypeAdapter<T>) new ParamsAdapter();
    }

    return null;
  }

  private static final class ParamsAdapter extends TypeAdapter<Params> {

    @Override public void write(JsonWriter jsonWriter, Params params) throws IOException {

      if (params == null) {

        jsonWriter.nullValue();
        return;
      }

      jsonWriter.beginObject();

      Map<String, String> map = params.getExtrasMap();

      for (String key : map.keySet()) {

        jsonWriter.name(key);
        jsonWriter.value(map.get(key));
      }

      jsonWriter.endObject();
    }

    @Override public Params read(JsonReader jsonReader) throws IOException {

      if (jsonReader.peek() == JsonToken.NULL) {

        jsonReader.nextNull();
        return null;
      }

      Params.Builder builder = new Params.Builder();

      jsonReader.beginObject();

      while (jsonReader.hasNext()) {

        String key = jsonReader.nextName();
        String value = jsonReader.nextString();

        builder.put(key, value);
      }

      jsonReader.endObject();

      return builder.create();
    }
  }
}

PS:灵感来自 auto-value-factory

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
搭载 M1 芯片的苹果 Mac电脑,重装 macOS 可能变「砖头」
SegmentFault 思否消息,在苹果新推出的搭载 M1 芯片的 Mac 电脑后不久,有网友发现新款 Mac 在重装系统时会出现「An error occurred while preparing the update。 Failed to personalize the software update。 Please try again」(准备更新时发生错误。无法个性化软件更新,请再试一次)的错误。
用户7454708
2023/05/08
1.2K0
搭载 M1 芯片的苹果 Mac电脑,重装 macOS 可能变「砖头」
Mac系统重装指南(不抹盘):2023版保姆级教程,轻松解决macOS问题并保留数据和软件
本文为CSDN用户群体准备的Mac系统重装指南,详细介绍了在不抹盘的情况下如何重装系统,并保留Mac中的数据和软件。文章分为Apple芯片和Intel处理器的重装步骤,适用于不同类型的Mac机型。通过简单的操作,你可以轻松完成系统重装。
猫头虎
2024/04/08
3.2K0
Mac系统重装指南(不抹盘):2023版保姆级教程,轻松解决macOS问题并保留数据和软件
苹果要垄断?官方证实:T2芯片会限制新款Mac电脑第三方维修
目前,苹果还没有透露T2芯片将会限制哪些设备以及组件的维修,但是根据推断,它们包括新款Mac电脑的主板、Touch ID、屏幕、顶盖和内存等零部件。
镁客网
2018/12/13
8120
【Linux】学习Linux,需要借助具象化的思维
经过上一篇章的内容,我们简单了解了一下操作系统的发展史,同时还认识了几位顶级大佬。最后我们一起感受了一下Linux的操作环境,知道了在Linux环境下需要通过在命令行中输入指令的方式来进行。那这种通过命令行输入指令的方式与我们在Windows系统下通过鼠标进行的单击和双击又有什么区别呢?在今天的内容中,我们将来探讨一下命令行与图形化界面。
蒙奇D索隆
2024/09/01
920
【Linux】学习Linux,需要借助具象化的思维
嘿!你收到了一封苹果WWDC 2016的邀请函
昨天,苹果公司正式向媒体发布了WWDC 2016的邀请函,确定今年的苹果开发者大会将在太平洋时间6月13日上午10:00(北京时间6月14日凌晨01:00)开幕,整个大会将持续至当地时间6月17日。
镁客网
2018/05/28
4920
Tesler去世丨你逃不过复制粘贴,同样也逃不过Tesler定律
今天博文菌刷到了人机交互设计的先驱拉里·特斯勒(Larry Tesler)去世的消息,复制粘贴UI设计之父的title,让无数网友为之致敬。不过 Tesler带来的贡献却不仅如此——
博文视点Broadview
2020/06/12
6340
Tesler去世丨你逃不过复制粘贴,同样也逃不过Tesler定律
改变世界的6大计算机实验室
这儿我们将列出6大孕育数字时代的计算机实验室,正是它们不断地为计算机的发展事业添砖加瓦、保驾护航,才使得我们如今能够如此舒适得享受到这便捷的数字世界。
FPGA技术江湖
2021/09/09
7930
Mac苹果电脑安装Windows系列系统
描述:苹果电脑安装Windows系统是一部分人的想法(实际上不建议,发挥不出Mac笔记本的实际功能与效率); 但是苹果公司为了让Mac进入广阔的市场,开发了Bootcamp用Mac的应用帮助引导windows系统;
全栈工程师修炼指南
2020/10/26
3.5K0
Mac苹果电脑安装Windows系列系统
指令和界面【Linux】
Linux操作系统提供了丰富的命令行界面和图形用户界面工具,用户可以根据自己的需求选择适合的界面进行操作。命令行界面更加灵活和高效,适合熟悉命令的用户;图形用户界面更加直观和友好,适合新手用户。
鲜于言悠
2024/04/24
3020
指令和界面【Linux】
手把手教你Mac重装系统不再难:苹果电脑重装系统教程
我们在使用mac电脑的过程中,因为Mac电脑长时间使用或多或少都可能会出现一些问题,这个时候我们可以选择重新安装系统来解决这些问题。Mac电脑重装系统方法其实很简单,分为两种,一种可以在线重装系统,一种可以将Mac系统制作到U盘里进行系统重装。今天我们主要介绍如何在线重装系统的教程。
冬天真冷啊
2023/04/14
5.9K0
Mac电脑怎样关闭sip,苹果电脑关闭系统完整性保护SIP的方法
“xxx”因为出现问题而无法打开。请与开发者联系,以确定“xxx”可以配合Macos版本使用。您可能需要重新安装应用程序。请务必安装适用于该应用程序和Macos的任何可用更新。点按“报告”以查看更详细的信息,并将报告发送给 Apple。
MAC先森
2019/09/29
2.3K0
MacBook Pro 为什么值得我写一篇博文——程序猿使用感悟
研究生生涯伊始,撑过大学四年的 Dell 灵越 N4050 笔记本电脑就再次罢工了,一直想换电脑的冲动终于要付诸行动了,本来准备再换一个性价比比较高的 win 系列笔记本就行了,但是让我意外的是研究生新入学后会发放奖学金....一下子换电脑的资金就富裕了,可选择的余地就更大了。对与苹果电脑的高逼格我是早就心驰神往,但比较高的售价与某些软件兼容性的顾虑一直是我购买的主要障碍,现在钱已经不是问题,剩下的就是考略兼容性以及实用性的问题了,性价比?买苹果就不要考了什么性价比了吧。
流川枫
2018/09/12
21.2K0
MacBook Pro 为什么值得我写一篇博文——程序猿使用感悟
关于苹果电脑制作启动U盘的归纳
今天出一期详细的苹果电脑IMac, Macbook,IMac mini,Mac PRO等制作安装苹果系统U盘的教程。
Khan安全团队
2022/05/17
5.4K0
关于苹果电脑制作启动U盘的归纳
苹果系统自带的计算机怎么恢复出厂设置,苹果电脑MacBook如何将系统恢复出厂设置…
有时候在使用电脑的过程中会出现问题,需要进行恢复出厂设置的操作。如果使用的是苹果电脑MacBook
全栈程序员站长
2022/09/07
3.9K0
Mac苹果笔记本u盘装系统教程-附所有版本MacOS原版镜像和TM镜像
后期不再单独发布镜像链接,所有的镜像都已经归类到下面这两个文件夹内,日后所有版本的Mac OS原版镜像和TM镜像都会直接上传到下面两个文件夹,保存下面两个文件夹的链接即可。
叼同学
2023/02/26
5.5K0
Mac苹果笔记本u盘装系统教程-附所有版本MacOS原版镜像和TM镜像
macbook开机登录时输入正确的密码却提示密码错误
Macbook正常的账户登录,提示密码错误,但是我输入的密码确认了几次都是完全正确的,就是死活登不上去一直显示密码错误,一搜索原来是操作系统BUG,有对应解决方案。
翎野君
2024/11/21
7160
忘记MacBook密码解决方法
其实相较于Windows,macOS整天哪哪都需要验证密码,更不容易忘,但这不是连MacBook AIr都有指纹识别了嘛,忘记密码的风险也就大了一些,了解一些技巧或多一手准备还是很有必要的。 和Windows一样,方法很多,Command + R + Terminal + resetpassword。对不对呢,也对,可以解决问题,但并非是所有情况下的最优解。下面和大家分享几种解决方案。
MAC先森
2019/08/30
3.1K0
揭秘:深入解读针对苹果Mac电脑的ROM级恶意软件“雷击(Thunderstrike)”
众所周知苹果Mac电脑很安全,但是随着恶意软件的发展,凭借现有Mac安全机制想要完全对抗恶意软件的感染可能会变得更加艰难。近期一种新型恶意软件的问世,使得黑客通过短暂的物理接触,让2011年以后生产的苹果Mac电脑感染ROM级恶意程序。 背景 近日,安全研究人员发现一种让苹果电脑感染ROM级恶意程序的方法。 这个攻击由编程专家Trammell Hudson在德国汉堡举办的年度混沌计算机大会上展现,他证明这将使重写苹果Mac计算机固件成为可能。 这种攻击被命名为“Thunderstrike(雷击)”。它实
FB客服
2018/02/05
1.5K0
揭秘:深入解读针对苹果Mac电脑的ROM级恶意软件“雷击(Thunderstrike)”
电脑技巧:20个电脑冷知识,你都知道吗?
1971年,电脑工程师雷·汤姆林森在ARPANET(互联网的前身)上发送了第一封电子邮件。这封邮件是从一台计算机发送到同一房间内的另一台计算机,内容为“QWERTYUIOP”,主要是为了测试一种能够发送信息给其他网络用户的新型程序。这次尝试标志着电子邮件作为一种通信方式的诞生。
小明互联网技术分享社区
2024/07/02
4120
电脑技巧:20个电脑冷知识,你都知道吗?
推荐阅读
相关推荐
搭载 M1 芯片的苹果 Mac电脑,重装 macOS 可能变「砖头」
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验