Gson中@JsonAdater注解的几种方式总结

目录
  • Gson @JsonAdater注解的几种方式
    • 总结
    • 问题描述
    • 方式一
    • 方式二-write原样
    • 方式三-简单写法
  • Gson注解
    • @SerializedName
    • Expose

Gson @JsonAdater注解的几种方式

总结

可以通过自定义TypeAdapter和TypeAdapterFactory的方式,自定义gson的序列化和反序列规则,TypeAdapterFactory可以拿到上下文gson、TokenType类型;

也可以通过继承JsonReader重新写一次代码,在beginArray和endArray想办法跳过array的string形式的左右 双引号", gson.fromJson(myJsonReader, Type)也可以实现 解析时自动将String变为List,但采用注解@JsonAdapter的方式更为正规一些;

问题描述

json字符串:

{
    "cityIds": "[1,2,1001,13131]",
    "types": "[{\"name\": \"biz\",\"details\": [1]}]"
}

java对象定义:

 @Data
    public static class RequestParams {
       // json字符串里对应的是String
        private List<TypeItem> types;
        private List<Integer> cityIds;
    }
    @Data
    public static class TypeItem {
        private String name;
        private List<Integer> details;
    }

可以看到json里面cityIds和types都是String,而pojo里则是List,使用gson的fromJson将json转为pojo会发生报错

方式一

  @JsonAdapter(StringCollectionTypeAdapterFactory.class)
     private List<TagItem> tags;
     @JsonAdapter(StringCollectionTypeAdapterFactory.class)
     private List<Integer> cityIds;
public static class StringCollectionTypeAdapterFactory implements TypeAdapterFactory {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
            // 为了write的时候能使用到elementTypeAdapter
            Type type = typeToken.getType();
            Class<? super T> rawType = typeToken.getRawType();
            if (!Collection.class.isAssignableFrom(rawType)) {
                return null;
            }
            Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
            TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
            
            TypeAdapter<T> result = new Adapter(gson, elementTypeAdapter, typeToken);
            return result;
        }
        private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
            private final TypeAdapter<E> elementTypeAdapter;
            private final Gson gson;
            private final TypeToken listType;
            public Adapter(Gson context, TypeAdapter<E> elementTypeAdapter, TypeToken listType) {
                this.elementTypeAdapter = elementTypeAdapter;
                this.gson = context;
                this.listType = listType;
            }
            @Override public Collection<E> read(JsonReader in) throws IOException {
                if (in.peek() == JsonToken.NULL) {
                    in.nextNull();
                    return null;
                }
                List<E> list = gson.fromJson(in.nextString(), listType.getType());
                return list;
            }
 
            // write后可以将array的string格式,重新变成array
            @Override public void write(JsonWriter out, Collection<E> collection) throws IOException {
                if (collection == null) {
                    out.nullValue();
                    return;
                }
                out.beginArray();
                for (E element : collection) {
                    elementTypeAdapter.write(out, element);
                }
                out.endArray();
            }
        }
    }

方式二-write原样

public static class StringCollectionTypeAdapterFactory1 implements TypeAdapterFactory {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
            return new Adapter(gson, typeToken);
        }
        private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
            private final Gson gson;
            private final TypeToken listType;
            public Adapter(Gson context, TypeToken listType) {
                this.gson = context;
                this.listType = listType;
            }
            @Override public Collection<E> read(JsonReader in) throws IOException {
                if (in.peek() == JsonToken.NULL) {
                    in.nextNull();
                    return null;
                }
                List<E> list = gson.fromJson(in.nextString(), listType.getType());
                return list;
            }
            @Override public void write(JsonWriter out, Collection<E> collection) throws IOException {
                if (collection == null) {
                    out.nullValue();
                    return;
                }
                out.value(gson.toJson(collection));
            }
        }
    }

方式三-简单写法

private static class CollectionStringTypeAdapterFactory implements TypeAdapterFactory {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                    if (value == null) {
                        out.nullValue();
                        return;
                    }
                    gson.getAdapter(type).write(out, value);
                }
                @Override
                public T read(JsonReader in) throws IOException {
                    if (in.peek() == JsonToken.NULL) {
                        return null;
                    }
                    if (in.peek() == JsonToken.BEGIN_ARRAY) {
                        return gson.getAdapter(type).read(in);
                    }
                    T collection = gson.fromJson(in.nextString(), type.getType());
                    return collection;
                }
            };
        }
    }

测试用例如下所示:

@Test
    public void testGson1() {
        Gson gson = new Gson();
        RequestParams requestParam;
        String json;
        // 1.自动将string转为属性的List
        json = "{\"id\": \"000000\",\"types\": \"[{\\\"name\\\":\\\"name1\\\",\\\"list\\\":[1,2]},{\\\"name\\\":\\\"name2\\\",\\\"list\\\":[3,4]}]\",\"keywordIds\": \"[12,13]\"}";
        System.out.println(json);
        requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
        Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
        System.out.println(gson.toJson(requestParam));
        // 2.jsonArray也可以转为List
        json = "{\"id\": \"000000\",\"keywordIds\": [12,13],\"types\": [{\"name\":\"name1\",\"list\":[1,2]},{\"name\":\"name2\",\"list\":[3,4]}]}";
        requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
        Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
        System.out.println(gson.toJson(requestParam));
        // 3.换行的方式呢
        json = "{\n" +
                "\t\"id\": \"000000\",\n" +
                "\t\"keywordIds\": [12,13],\n" +
                "\t\"types\": [{\"name\":\"name1\",\"list\":[1,2]},{\"name\":\"name2\",\"list\":[3,4]}]\n" +
                "}";
        requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
        Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
        System.out.println(gson.toJson(requestParam));
        // 4.能否将List里面的Integer变成String呢
        json = "{\n" +
                "\t\"id\": \"000000\",\n" +
                "\t\"keywordIds\": [12,13],\n" +
                "\t\"types\": [{\"name\":\"name1\",\"list1\":[1,2]},{\"name\":\"name2\",\"list1\":[3,4]}]\n" +
                "}";
        requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
        Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
        System.out.println(gson.toJson(requestParam));
        // 5.能否将List里面的Integer变成String
        json = "{\n" +
                "\t\"id\": \"000000\",\n" +
                "\t\"keywordIds1\": [12,13],\n" +
                "\t\"types\": [{\"name\":\"name1\",\"list1\":[1,2]},{\"name\":\"name2\",\"list1\":[3,4]}]\n" +
                "}";
        requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
        Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
        System.out.println(gson.toJson(requestParam));
        // 6.自动将string转为属性的List, 并且list里面的Integer变为String
        json = "{\"id\": \"000000\",\"types\": \"[{\\\"name\\\":\\\"name1\\\",\\\"list1\\\":[1,2]},{\\\"name\\\":\\\"name2\\\",\\\"list1\\\":[3,4]}]\",\"keywordIds1\": \"[12,13]\"}";
        System.out.println(json);
        requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
        Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
        System.out.println(gson.toJson(requestParam));
    }
    @Data
    public static class RequestParams {
        private String id;
        @JsonAdapter(CollectionStringTypeAdapterFactory.class)
        private List<TypeItem> types;
        @JsonAdapter(CollectionStringTypeAdapterFactory.class)
        private List<Integer> keywordIds;
        @JsonAdapter(CollectionStringTypeAdapterFactory.class)
        private List<String> keywordIds1;
    }
    @Data
    public static class TypeItem {
        private String name;
        private List<Integer> list;
        private List<String> list1;
    }

Gson注解

@SerializedName

主要应用在Gson解析json字符串时。Gson能直接将json字符串解析成java对象或者集合,也能将java对象转换为json字符串表示。例如有json数据如下:

{
    "id":"1"
    "n":"zhangsan"
    "p":"123456"
    "s":"0"
}

它能被解析到下面这个对象

public class User{
    private String id;
    private String n;
    private String p;
    private string s;
}

默认在字段名相同的字段间解析,所以User类必须要这样写才能直接使用Gson解析出来,但是java对象里的属性名和json里的字段名有时会不一样。Gson提供注解的方法来解决这个问题。

public class User{
 
    private String id;
 
    @SerializedName("n")
    private String userName;
 
    @SerializedName("p")
    private String password;
 
    @SerializedName("s")
    private String sex;
}

Expose

通常与@SerializedName连用,当我们不想把某个属性包含到json中时可以用。

public class UserSimple {  
    @Expose()
    String name; // equals serialize & deserialize
 
    @Expose(serialize = false, deserialize = false)
    String email; 
 
    @Expose(serialize = false)
    int age; 
 
    @Expose(deserialize = false)
    boolean isDeveloper; // equals only serialize
}

序列化的结果将只有name和isDeveloper出现在json中,因为serialize都是false。反序列化时,java对象将只会拥有json中的name和age,因为diserialze是true。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Gson序列化指定忽略字段的三种写法详解

    目录 1. transient关键字 2. expose注解 3. 自定义排查策略ExclusionStrategy 在我们日常使用json序列化框架过程中,经常会遇到在输出json字符串时,忽略某些字段,那么在Gson框架中,要想实现这种方式,可以怎么处理呢? 本文介绍几种常见的姿势 1. transient关键字 最容易想到的case,就是直接借助jdk的transient关键字来修饰不希望输出的对象,如 @Data @AllArgsConstructor @NoArgsConstructo

  • JAVA使用Gson解析json数据实例解析

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成.同XML一样是一种"传输格式".JSON采用与编程语言无关的文本格式,便于数据传输.存储.交换. 封装类Attribute: public class Attribute { private int id; private String name; private int age; public int getId() { return id; } p

  • GSON实现Java对象与JSON格式对象相互转换的完全教程

    Gson是一个Java库,用来实现Json和Java对象之间的相互转换.Gson是一个托管在https://github.com/google/gson的开源项目. Gson中主要的类是Gson,也可以使用类GsonBuilder在创建Gson对象的同时设置一些选项. Gson对象在处理Json时不会保存任何状态,所以使用者能够很轻松的对同一个Gson对象进行多次序列化.反序列化等操作. 示例:基本使用 //Serialization Gson gson = new Gson(); gson.t

  • Gson中@JsonAdater注解的几种方式总结

    目录 Gson @JsonAdater注解的几种方式 总结 问题描述 方式一 方式二-write原样 方式三-简单写法 Gson注解 @SerializedName Expose Gson @JsonAdater注解的几种方式 总结 可以通过自定义TypeAdapter和TypeAdapterFactory的方式,自定义gson的序列化和反序列规则,TypeAdapterFactory可以拿到上下文gson.TokenType类型: 也可以通过继承JsonReader重新写一次代码,在begin

  • 详析Spring中依赖注入的三种方式

    前言 平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. 在Sprin

  • mybatis中批量插入的两种方式(高效插入)

    MyBatis简介 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 一.mybiats foreach标签 foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合.foreach元素的属性主

  • 详解Spring Boot 中实现定时任务的两种方式

    在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式. @Scheduled 使用 @Scheduled 非常容易,直接创建一个

  • Spring容器中添加bean的5种方式

    目录 @Configuration + @Bean @Componet + @ComponentScan @Import注解导入 @Import直接导入类 @Import + ImportSelector @Import + ImportBeanDefinitionRegistrar @Import + DeferredImportSelector 使用FactoryBean接口 使用 BeanDefinitionRegistryPostProcessor 小结 我们知道平时在开发中使用Spri

  • ASP.NET Razor模板引擎中输出Html的两种方式

    本文实例讲述了ASP.NET Razor模板引擎中输出Html的两种方式.分享给大家供大家参考,具体如下: Razor中所有的Html都会自动编码,这样就不需要我们手动去编码了(安全),但在需要输出Html时就是已经转义过的Html文本了,如下所示: @{ string thisTest = "<span style=\"color:#f00;\">qubernet</span>"; } @thisTest; 这样在页面输出的文本就是:<

  • JS中检测数据类型的几种方式及优缺点小结

    1.typeof 用来检测数据类型的运算符 typeof value 返回值首先是一个字符串,其次里面包含了对应的数据类型,例如:"number"."string"."boolean"."undefined"."object"."function" 局限性: 1)typeof null ->"object" 2)检测的不管是数组还是正则都返回的是"ob

  • mysql命令行中执行sql的几种方式总结

    1.直接输入sql执行 MySQL> select now(); +---------------------+ | now() | +---------------------+ | 2013-09-18 13:55:45 | +---------------------+ 1 row in set (0.00 sec) 2.执行编写好的sql脚本 mysql> source H:/1.sql +---------------------+ | now() | +--------------

  • jQuery中map函数的两种方式

    两种方式: 1.直接jQuery.map //将原数组中每个元素加 4 转换为一个新数组. $.map( [0,1,2], function(n){ return n + 4; }); //结果: [4, 5, 6] //原数组中每个元素扩展为一个包含其本身和其值加 1 的数组,并转换为一个新数组 $.map( [0,1,2], function(n){ return [ n, n + 1 ]; }); //结果: [0, 1, 1, 2, 2, 3] 2.遍历对象.map 例子: <form

  • Java中实现线程的三种方式及对比_动力节点Java学院整理

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法,run方法的方

随机推荐