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。

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

Gson中@JsonAdater注解的几种方式总结的更多相关文章

  1. android – 如何使用GSON发布大型json文件解析的进度

    亲爱的Stackoverflowers,我目前正在从我的原始资源中解析一个大的json文件.我不得不逐行更改读取使用Reader对象和gson,以逃避内存不足异常.到现在为止还挺好.现在这一切都发生在异步任务中,我希望通过使用publishProgress()让用户通知某种加载屏幕的进度.这是我现在正在阅读文件的方式,但我不知道是否我可以从GSON或Reader对象获得任何类型的进度更新.任何帮助是极大的赞赏!解决方法您必须围绕InputStream编写包装器.像这样的东西应该工作:如何使用:

  2. android – IncompatibleClassChangeError com.google.gson.annotations.SerializedName.value

    当用户从Play商店更新应用程序时,我们在Samsung设备中收到IncompatibleClassChangeError.请检查下面的日志.代码如下:LoginResponse是我的POJO课程.将返回JSON字符串,这是服务器响应.解决方法看起来像三星问题..很多人不仅与gsonlib有同样的问题,而且还有其他库.我认为你不能做太多,只等三星开发人员解决这个问题.已经这个问题是在三星开发者论坛

  3. android – Gson中的RuntimeException解析JSON:无法调用受保护的java.lang.ClassLoader()而没有args

    我假设我可以通过单独保存位置对象中的关键字段来解决这个问题,但如果可能的话,保存位置对象会很好.我看到有一个ExclusionStrategy对象可用于排除字段,但我不确定是否可以/应该使用它来排除我位置内的额外内容…

  4. Android Twitter Fabric SDK与Google GSON发生冲突

    我在将TwitterFabricSDK集成到我的应用程序时遇到了困难.我按照Twittertutorial的步骤进行操作,但是当我尝试用gradle构建我的项目时,我得到了这个错误:我尝试从我的app模块lib文件夹中删除我的静态Gson库,之后一切都很顺利.删除从gradle模块依赖项添加twittersdk的行时也一样,所以我很确定这两者之间存在某种冲突,我正在寻求解决它.任何帮助将不胜感激!

  5. android – 用gson解析JSON对象

    我正在尝试解析JSON,如:有了GSON,制作但是获得错误预期BEGIN_ARRAY但在第1行第2列是BEGIN_OBJECT如何在数组中解析这些数字?解决方法您将首先想要创建一个模型类,GSON可以将您的json绑定到:然后你可以打电话

  6. android – 如何通过Retrofit在@Query中传递自定义枚举?

    我将toString()用于其他目的.解决方法正如@DawidSzydo所提到的,我在Retrofit中误解了Gson的用法.它仅用于响应/请求解码/编码,但不用于@Query/@Url/@Pathe.t.c.对于他们来说,Retrofit使用Converter.Factory将任何类型转换为String.以下是将@Serializedname作为任何Enum的值传递给Retrofit服务时自动使用的代码.转换器:EnumUtils:改造创造:08.18更新添加kotlin类似物:在日志中,您将看到:使用

  7. android – GSON反序列化自定义对象数组

    我正在尝试使用GSON在Android中序列化/反序列化JSON.我有两个类看起来像这样:和:我正在使用GSON来序列化/反序列化数据.我像这样序列化:这将生成如下所示的JSON:我这样反序列化:我打电话的时候收到错误.我不知道这个错误意味着什么.我不认为自己做了任何严重的错误.有帮助吗?解决方法将您的代码更改为:使用Interfaces是一个很好的做法,GSON要求.Gson将javascript中的数组“[]”转换为LinkedList对象.在您的代码中,GSON尝试在_users字段中注入一个Lin

  8. android – 使用GSON解析并放入对象列表

    我发现这篇文章:http://www.dev-articles.com/article/Google-gson-and-list-of-objects-386003看起来它正在尝试做我想要的,它解析我的json并将它们放入对象列表中.我没有得到的,或者文章遗漏的东西,是“Project”类如何被使用.它似乎无处不在.编辑:感谢yorkw,我现在有:但是我在Type上获得了红色标记.“类型无法解析为

  9. android – Retrofit:如何在请求中指定逗号分隔的参数?

    我正在尝试重构我的代码以使用Retrofit进行一些FoursquareAPI调用,但是没有找到一个正确的示例来说明如何指定一个查询参数,该参数有两个用逗号分隔的值.我的基本网址如下:我的其余网址是这样的:我的界面的第一个实现:然后提出这样的请求:但是,上面给了我以下错误:第二个实现(在查看一些使用Query参数的SO响应之后.注意:一旦我找到了ll?对于基本相同的问题,它们是不同的工具.>利用Retrofit的内置转换器机制;)从单词到代码:共:

  10. Android studio Gradle无法找到方法compile()

    过去两天我试图找到解决这个问题的方法,但没有运气.我想尝试包含GSONlib.进入我的android项目.这是我的文件夹结构的图片:现在在我的build.gradle中,我有以下内容:我也右键单击了gson-2.2.4.jar并将其添加为lib.当我编译时,我得到以下错误:谁能帮我这个?如果您需要更多信息,请告诉我!和接受的答案.两个答案都说同样的话.添加/导入jar文件并编辑build.gradle文件后,gradlew清理.HTH.编辑:有两个build.gradle文件.您应该编辑项目文件夹下的bu

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部