JsonDeserializer——Gson自定义解析类型错误的字段

SpringBoot使用@JsonDeserialize和@JsonSerialize注解的功能简介说明 Springboot项目中@JsonProperty不生效的解决方法分享 阅读详情

在开发中,定义好实体类和相应字段,Gson就可以很方便地帮助我们实现序列化和反序列化。

可是有时候,后台传给客户端的json数据格式有误,其中的某些字段类型错误,即,和我们在实体类中定义的字段类型不一致,此时就会出现类型转换错误,app原地爆炸!

假设有这么一个类Phone代表手机:

/**
 * Author: Sbingo
 * Date:   2017/4/23
 */

public class Phone {

    /**
     * 手机大小
     */
    private Size size;
    /**
     * 手机内app列表
     */
    private List<App> apps;

    public Size getSize() {
        return size;
    }

    public void setSize(Size size) {
        this.size = size;
    }

    public List<App> getApps() {
        return apps;
    }

    public void setApps(List<App> apps) {
        this.apps = apps;
    }
}

其中类Size如下:

/**
 * Author: Sbingo
 * Date:   2017/4/23
 */

class Size {

        private String length;
        private String width;
        private String height;

        public String getLength() {
            return length;
        }

        public void setLength(String length) {
            this.length = length;
        }

        public String getWidth() {
            return width;
        }

        public void setWidth(String width) {
            this.width = width;
        }

        public String getHeight() {
            return height;
        }

        public void setHeight(String height) {
            this.height = height;
        }
    }

类App如下:

/**
 * Author: Sbingo
 * Date:   2017/4/23
 */

class App {
        private String appName;
        private String developer;

        public String getAppName() {
            return appName;
        }

        public void setAppName(String appName) {
            this.appName = appName;
        }

        public String getDeveloper() {
            return developer;
        }

        public void setDeveloper(String developer) {
            this.developer = developer;
        }
    }

对于类Phone,实际中我碰到的数据类型错误情况有:

对象size变成了字符串;

数组apps变成了字符串;

下面将会针对这两种错误分别讨论,其他错误可以类似处理。

当然这里的字符串是带有转义字符的json字符串,还是包含正确信息的。因此以下对字符串的处理可能只适应这种错误情况。

如何解决这一问题?

最好的办法当然是后台确保数据类型正确,从源头上消灭问题。

作为客户端开发,我们也要做好错误处理,应对各种场景。

客户端怎么处理?

registerTypeAdapter

其实Gson允许我们自定义解析某种类型的数据,一般我们使用Gson可能就直接new出来一个,但如果这样实例化:

Gson gson = new GsonBuilder()
            .registerTypeAdapter(A.class, new ADeserializer())
            .registerTypeAdapter(B.class, new BDeserializer())
            .create()

得到的gson就会使用自定义的ADeserializer和BDeserializer分别反序列化类A和类B。

`registerTypeAdapter 方法用于配置Gson的序列化或反序列化,接收两个参数。

第一个参数是注册的类型,即希望自定义解析的数据类型。

第二个参数包含了自定义的解析过程,它必须至少是TypeAdapter、InstanceCreator、JsonSerializer、JsonDeserializer四者之一的实现。

JsonDeserializer

泛型接口JsonDeserializer中的方法deserialize允许我们自定义反序列化过程,返回相对应的对象。

该方法接收三个参数,Gson会在进行相应类型字段的反序列化时回调该方法。

第一个参数类型为JsonElement,其中包含了真实返回的数据,它是一个抽象类,可以是JsonObject、JsonArray、JsonPrimitive、JsonNull四者之一,看名字也能知道这四者的大致类型。

第二个参数是当前反序列化的数据类型。

第三个是上下文参数context。

在自定义反序列化时,我们要分别处理数据类型正确和错误的情况,具体处理过程视数据而定,以下仅供参考。

错误一:对象size变成了字符串

字段size为Size对象类型,当后台接口返回了字符串时,可以只对Size类型自定义反序列化,如下:

/**
 * Author: Sbingo
 * Date:   2017/4/23
 */

public class SizeDeserializer implements JsonDeserializer<Size> {
    @Override
    public Size deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Size size = new Size();
        if (json.isJsonObject()) {
            //类型正确
            JsonObject jsonObject = json.getAsJsonObject();
            size.setLength(jsonObject.get("length").getAsString());
            size.setWidth(jsonObject.get("width").getAsString());
            size.setHeight(jsonObject.get("height") == null ? "" : jsonObject.get("height").getAsString());
        } else {
            //类型错误
            String value = json.getAsString();
            size = new Gson().fromJson(value, Size.class);
        }
        return size;
    }
}

泛型参数传入Size,当反序列化Size对象时,就会回调我们自定义的方法。

首先用isJsonObject()判断是否为对象

如果是,说明类型正确,接着依次设置各字段值。如果有些字段接口可能不会返回,记得判空,例如字段height。

如果类型错误,我遇到的错误情况只会是带有转义字符的字符串,所以直接按此处理了。调用json.getAsString()就能得到正确的json字符串,再通过Gson直接转换为Size类型。

这样不管接口返回数据中字段size类型正确与否,都能从容应对!

错误二:数组apps变成了字符串

字段apps是一个list,接口应该返回一个数组,如果类型错误,可以有两种方式来自定义解析,在我看来,这两种各有优劣,具体使用要结合实际。

自定义解析字段本身

这种方法和解析size类似,都是本着“谁类型错了,就解析谁”的原则。

由于没有找到用List作为泛型参数的方法,所以需要把类Phone中的字段apps从list改成数组,如果真只能改成数组,使用方便性可能较list略差。

定义AppDeserializer如下:

/**
 * Author: Sbingo
 * Date:   2017/4/23
 */

public class AppDeserializer implements JsonDeserializer<App[]> {


    @Override
    public App[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonArray()) {
            //类型正确
            JsonArray jsonArray = json.getAsJsonArray();
            App[] apps = new App[jsonArray.size()];
            for (int i = 0; i < jsonArray.size(); i++) {
                App app = new App();
                //获取app方法一
                JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
                app.setAppName(jsonObject.get("appName") == null ? "" : jsonObject.get("appName").getAsString());
                app.setDeveloper(jsonObject.get("developer") == null ? "" : jsonObject.get("developer").getAsString());
                //获取app方法二
//                app = context.deserialize(jsonObject, App.class);
                apps[i] = app;
            }
            return apps;
        } else if (json.isJsonObject()) {
            //类型错误1
            return null;
        } else if (json.isJsonPrimitive()) {
            //类型错误2,多为String
            String value = "";
            try {
                value = json.getAsString();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if ("".equals(value)) {
                return null;
            } else {
                App[] apps = new Gson().fromJson(value, App[].class);
                return apps;
            }
        } else {
            //一般不出现这种情况
            return null;
        }
    }
}

泛型参数传入数组,当反序列化App类型的数组时,就会回调我们自定义的方法。

首先用isJsonArray()类型是否正确,正确时获取数组也有两种方法,如代码所示,

方法一和之前的分析差不多。

方法二注意context反序列化时要避免进入死循环。

类型错误时做了较多区分,具体还是要看实际情况。

自定义解析字段所在类

这种方法以错误字段apps所在类Phone为处理类型,好处是字段apps还是可以用list,但如果类中很多其他字段,工作量就大了一些,幸好此处只还有一个size。

定义AppListDeserializer如下:

/**
 * Author: Sbingo
 * Date:   2017/4/23
 */

public class AppListDeserializer implements JsonDeserializer<Phone> {
    @Override
    public Phone deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Phone phone = new Phone();
        JsonObject jsonObject = json.getAsJsonObject();
        //此时不考虑size的类型错误情况
        if (jsonObject.get("size") != null) {
            jsonObject = jsonObject.get("size").getAsJsonObject();
            Size size = context.deserialize(jsonObject, Size.class);
            phone.setSize(size);
        }
        JsonElement appsArray = jsonObject.get("apps");
        if (appsArray != null) {
            List<App> apps = new ArrayList<>();
            if (appsArray.isJsonArray()) {
                //类型正确
                JsonArray jsonArray = appsArray.getAsJsonArray();
                for (int i = 0; i < jsonArray.size(); i++) {
                    JsonObject jo = jsonArray.get(i).getAsJsonObject();
                    App app = context.deserialize(jo, App.class);
                    apps.add(app);
                }
            } else {
                //类型错误
                String value = appsArray.getAsString();
                App[] a = new Gson().fromJson(value, App[].class);
                apps = Arrays.asList(a);
            }
            phone.setApps(apps);
        }
        return phone;
    }
}

泛型参数传入Phone,当反序列化Phone类型数据时,就会回调我们自定义的方法。

因为这里处理的是字段apps,所以不考虑字段size的类型正确与否。

Phone可以确定是个对象,所以直接用getAsJsonObject()方法获取一个JsonObject。

之后分别设置字段size和apps,其中用到的一些方法和上面类似。

JsonDeserializer自定义反序列化的思路大致就是这样,以后处理类似错误自当666。

Gson库详解:Java对象与JSON转换实战指南 JSON作为轻量级数据交换格式,在现代软件开发中广泛应用于API通信和配置管理。其核心原理是通过键值对结构实现数据的序列化与反序列化。Java生态中,Gson库凭借零配置设计和高效转换能力,成为处理JSON数据的首选工具之一。通过反射机制,Gson能自动映射Java对象字段与JSON属性,支持复杂对象图和泛型集合。开发实践中,Gson特别适合RESTful接口开发、配置文件解析等场景,与Spring Boot等框架集成良好。相比Jackson等其他JSON库,Gson在易用性和Android兼容性方面表现突 阅读详情

相关推荐

【jackson】@JsonDeserialize 和 @JsonSerialize

文章目录1.概述2.【需求】3.【实现方式】3.1 @JsonDeserialize3.2 @JsonSerialize4.案例4.1 实体类4.2 GenderJsonDeserializer4.3 GenderJsonSerializer4.4 controller5.【测试】5.1 测试保存,即 Controller 中的 savePerson()5.2 测试获取 1.概述 转载:@JsonDeserialize 和 @JsonSerialize 基本使用 学习这个主要是项目中国遇到了这个问题,然后

九师兄 3714

jackson自定义反序列化器JsonDeserializer

1.JSON的序列化与反序列化 JSON序列化:将实体类对象转为JSON字符串 JSON反序列化:将JSON字符串转为实体类 2.jackson和gson jackson作为Spring MVC和Spring Boot默认的JSON解析器,其与gson的工作原理不一样。 jackson通过调用实体类每个属性get/set方法进行注入,而gson则是通过设置每个属性为可访问后注入。 jackson工作原理大致如下 //获取Class对象 Class<Order.OrderStatus> order

weixin_43335392的博客 1万+

GPU运维面试题

【代码】GPU运维面试题。

u011220233的博客 700

JsonDeserialize序列化和反序列化(JSON转Java对象,反之)

JsonDeserialize注解是Jackson库提供的一种注解,用于指定反序列化时使用的自定义反序列化器。作为Jackson库的一部分,JsonDeserialize注解可以在Java对象和JSON数据之间进行转换。JsonDeserialize注解一般用于反序列化时需要进行特殊处理的情况,比如将一个JSON中的String类型字段解析为Java对象。通过本文的介绍,我们可以了解到JsonDeserialize注解的作用,以及如何使用该注解来实现不同的反序列化需求。

好幸运 5384

logisim实验——通过2个半加器实现1-bit全加器,通过4个一位全加器构成4-bit加法器(详解)

一、由异或门和与门所构成的半加器: 二、由两个半加器构成的1-bit全加器: ..

zep 1万+

【传感器标定(三):激光雷达标定原理与实现详解】

本文系统介绍了激光雷达标定的基本原理与方法。主要内容包括:激光雷达标定的分类(内参标定和外参标定)、坐标系定义和刚体变换数学基础;详细阐述了测距误差和光束方向两种内参标定方法;重点分析了基于目标(平面标定板、三维标定物)和基于运动(手眼标定、点云配准)的外参标定方法;介绍了多传感器联合标定技术及非线性优化、鲁棒标定等实现方法;最后提出了定量和定性两种标定评估体系。为激光雷达在自动驾驶等领域的精确应用提供了系统的标定技术指导。

weixin_47429781的博客 3793

了解 @JsonDeserialize 和 @JsonSerializer :优化 Java 应用中的富文本处理

JsonDeserializer是Jackson库中的注解之一,用于定制JSON反序列化的过程。通过在自定义的反序列化器类上使用@JsonDeserializer注解,我们可以对特定类型的JSON数据进行灵活的处理。@JsonSerializer是Jackson库中的注解之一,用于定制JSON序列化的过程。通过在自定义的序列化器类上使用@JsonSerializer注解,我们可以对特定类型的Java对象进行灵活的序列化处理。

~ 3727

Hierarchical Flow Partition(Top-down&&Bottom-up)

hierarchy flow是将设计切分成多个block,分别处理单个block,然后完成后,将它们进行拼接以完成最终的chip。一般划分为三个阶段:chip planning;physical budget就是pin assignmenthierarchy flow实现的方法有两种,一种是top-down,另一种是bottom-up,无论是哪种,都是都要通过flatten的方法分别全局范围进行优化实现。

qq_39493558的博客 3072

关于使用Gson解析包含Date类型数据是报错Caused by: java.text.ParseException: Failed to parse date ["1461689198000']:

当Gson解析包含Date(时间精确到毫秒级)时,直接转换是由问题的,即类型转换会失败,所以会报错。 需要自定义gson,实现转换。如下,即可解决。(Stack Overflow是利器啊!!!) // Creates the json object which will manage the information received GsonBuilder builder = new Gs...

black_swan_92的博客 908

Delphi 12社区版免费了!手把手教你搭建跨平台开发环境(Windows/macOS/Android/iOS)

本文详细介绍了如何利用新发布的Delphi 12社区版,免费搭建支持Windows、macOS、Android和iOS的跨平台开发环境。内容涵盖从环境准备、安装、配置各平台SDK(包括Android与macOS/iOS的PAServer连接),到创建首个FireMonkey跨平台应用、集成数据库以及调试部署的完整实战流程,帮助开发者零成本启动高效开发。

butter的博客 979

你学Simulink--基于储能系统的建模与仿真场景:飞轮储能系统在电网调频中的作用仿真

本文详细介绍了利用Simulink+Simscape搭建飞轮储能系统(FESS)电网调频仿真模型的全过程。主要内容包括:系统工作原理及调频作用分析,基于Simulink的模块化建模步骤(飞轮、电机/发电机、功率电子接口等组件搭建),调频控制策略实现(频率检测、功率指令生成和模式切换),以及仿真参数设置与结果分析方法。该模型可有效模拟FESS在电网频率调节中的快速响应特性,为新能源存储和智能电网研究提供重要仿真工具,同时可通过参数优化和算法改进进一步提升系统性能。

xiaoheshang_123的博客 168

Gson实战避坑:TypeToken、字段映射、自定义适配器与流式解析

JSON是Java服务端与前端交互的核心数据格式,合理选择并深度掌握一款JSON解析库,是每个Java开发者的基本功。Gson作为Google出品的轻量级JSON库,以零依赖、API简洁、反射容错性强等优势,在Android和服务端项目中长期占据重要生态位。然而在实际工程中,泛型擦除导致List<User>被反序列化成LinkedTreeMap、前后端字段命名风格不一致、Java 8时间类型LocalDateTime无法直接解析等,都是高频踩坑点。本文从TypeToken的泛型捕获原理切入,讲解如何正确携带

weixin_34199764的博客 230

一键开关机电路

一键开关机电路

让你爱上电路设计 4180

Gson对异常数据的解析类型容错

最近的项目中遇到过 前端的实体中定义的类型,经常与后端对不上 比如字段属性为 float,结果返回 “”; 这种类型对应不上的解析,Gson会抛出错误,整个解析全跪; 目前的需求是想提高解析的容错性,(至少ios在这个方面是第三方框架很好的容错机制) 经过百度后,发现了Gson的健壮性,是可以扩展了。 ## 探索1 ## TypeAdapter public abstract ...

zhangnx 5475

# 【WorkBuddy专栏33】工作空间,最大的WorkBuddy技巧——任务隔离、记忆分区与多项目管理实战

工作空间,最大的WorkBuddy技巧——任务隔离、记忆分区与多项目管理实战

AI人人懂 2144

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Gson反序列化Deserializer详解

Gson JsonDeserializer

菜鸟博客 1万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

android gson数据解析,Android之Gson脏数据解析

在与后台数据交互中,总会遇到一些后台返回的脏数据,从而在用GsonFormat生成对象时报错。有数据时本来字段是一个对象,没数据时后台PHP返回的这个字段为“”,从而导致了数据解析错误,从而导致了异常。下面代码以此记录:/*** Gson解析工具类* @param */public class GsonUtils {/** GsonUtils 单实例 */private static Gson...

weixin_30533109的博客 415

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Android 开发,Gson 解析 JSON 数据,时间戳转换为 Date 类型时的问题:com.google.gson.JsonSyntaxException: 1753945106316

Android 开发,Gson 解析 JSON 数据,时间戳转换为 Date 类型时的问题:com.google.gson.JsonSyntaxException: 1753945106316

weixin_52173250的博客 171

Gson 常见问题排查指南:从异常信息到修复方案的完整实战手册

本指南基于 Gson 官方仓库的 `Troubleshooting.md` 整理而成,系统梳理了使用 Gson 进行 JSON 序列化/反序列化时最常遇到的 23 类问题,覆盖类型安全、Java 模块系统反射限制、Android 代码压缩(ProGuard / R8)、JSON 语法校验与字段输出等场景。阅读完本文,你将掌握每类异常的典型症状、根因分析思路,以及可直接落地的修复代码与配置,并能在源

gitblog_00109的博客 953

gson 怎么把空字符串去掉_Gson解析空字符串异常的处理

面对一些不规范的json,我们的gson解析经常会抛出各种异常导致app崩溃,这里可以采取一些措施来避免11月9日更新:关于数组类型的字段解析异常,我尝试了一些方案,但最后都存在问题,如果大家有好的解决方案,希望能贴在下面.不甚感激.异常示例=>正常json:{"code":0,"msg":"ok","data":[ //约定为数组{"id":5638,"newsId":5638}]}...

weixin_33229152的博客 1162

3步搞定复杂JSON!Gson自定义反序列化器实战指南

你是否还在为嵌套JSON结构解析头痛?当API返回的JSON格式与Java对象不匹配时,手动映射字段既繁琐又易错。本文将通过3个简单步骤,教你使用Gson自定义反序列化器轻松处理复杂JSON,让数据解析效率提升10倍!读完你将掌握:自定义反序列化器的创建方法、注册流程以及实战案例解析。 ## 为什么需要自定义反序列化器? 默认情况下,Gson通过反射机制将JSON字段与Java对象字段直接映射...

gitblog_01032的博客 322

gson 怎么把空字符串去掉_java相关:Gson解析空字符串发生异常的处理方法

java相关:Gson解析空字符串发生异常的处理方法发布于 2020-12-28|复制链接最近在一个项目中遇到一个问题,当面对一些不规范的json,我们的gson解析经常会抛出各种异常导致app崩溃,通过在网上查找资料,找到了原因,前言在实际开发项目中,服务器经常会用空字符串 “” 作为返回结果表示空值 ,但这在Gson当中就会遇到问题,如果这项数据的类型不是字符串,Gson解析就会报错Json异...

weixin_28795975的博客 353

Java JSON组装与解析实战:Jackson、Gson、Fastjson2选型与避坑指南

JSON序列化与反序列化是Java后端开发中处理接口数据的核心技术,其原理是通过对象映射器将Java对象与JSON字符串相互转换。合理选择Jackson、Gson或Fastjson2等库,能显著提升开发效率与系统稳定性。在微服务接口交互、第三方API对接、配置管理等场景中,JSON处理能力直接影响代码质量与运行安全。掌握字段映射、日期格式化、泛型还原等关键细节,可有效规避转义错误、类型丢失和循环引用等常见问题。本文系统梳理Java环境下JSON组装与解析的完整方案,涵盖选型对比、实操代码与排查经验。

weixin_34218579的博客 323

Gson-解析-Json-容错才是关键,举几个常用的实例!

【Android 详细知识点思维脑图(技能树)】其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

2401_84873858的博客 743

Gson 版本演进全解析:从 1.0 到 2.10 的 CHANGELOG 深度解读

Gson 是 Google 开源的 Java 序列化/反序列化库,用于在 Java 对象与 JSON 之间进行双向转换。本文以仓库中的 [CHANGELOG.md](https://link.gitcode.com/i/fc167c9843e8ebb5a4653eeaf498ceea) 为核心脉络,逐版本梳理 Gson 从 1.0 到 2.10 的功能演进、破坏性变更与性能优化,并结合 [gson

gitblog_01056的博客 840

Gson实战高阶技巧:TypeToken、自定义适配器与性能优化

JSON解析是Java服务端与Android开发中的基础工程能力,Gson凭借简洁API成为主流选择。其底层核心并非只有反射,而是基于TypeAdapter注册表与JsonElement树模型,理解这套机制才能应对复杂场景。TypeToken用于解决泛型擦除导致的类型信息丢失,自定义JsonDeserializer和TypeAdapter则可精准处理日期格式、BigDecimal精度、Long溢出等生产环境暗礁。流式JsonReader能在大字段场景下显著降低对象分配开销。此外,ProGuard混淆规则、s

weixin_32175665的博客 249
上一篇: Instant Run导致ClassNotFoundException
下一篇: 【源码分析】CountDownTimer倒计时为何如此优雅
binaryshao
博客等级 码龄11年 52粉丝 71原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值