美文网首页
20171122-fastJson、序列化、深拷贝

20171122-fastJson、序列化、深拷贝

作者: 好奇的小刺猬 | 来源:发表于2017-12-22 21:00 被阅读1013次

fastJson过滤器:

fastjson 过滤不需要的字段或者只要某些字段

/*
 * 第一种:在对象响应字段前加注解,这样生成的json也不包含该字段。
 * @JSONField(serialize=false)  
 * private String name;  
 */

/*
 * 第二种:在对象对应字段前面加transient,表示该字段不用序列化,即在生成json的时候就不会包含该字段了。
 * private transient  String name;  
 */

/*
 * 第三种:使用fastjson的拦截器
 * PropertyFilter profilter = new PropertyFilter(){  
  
            @Override  
            public boolean apply(Object object, String name, Object value) {  
                if(name.equalsIgnoreCase("last")){  
                    //false表示last字段将被排除在外  
                    return false;  
                }  
                return true;  
            }  
              
        };  
        json = JSON.toJSONString(user, profilter);  
        System.out.println(json);   
 */

/*
 * 第四种,直接填写属性
 * SimplePropertyPreFilter filter = new SimplePropertyPreFilter(TTown.class, "id","townname");  
    response.getWriter().write(JSONObject.toJSONString(townList,filter));   

 */

工具组同学在做热修复时发现一种robust不能兼容的情况。就是对对象进行序列化,这个对象会根据类的字段和方法自动生成serialVersionUID, robust插入代码后serialVersionUID变掉了,导致反序列化失败。
因为这个整理了下相关文档。
文档:

既然如此,那没有定义serialVersionUID的那些对象,被存入的本地文件,新版本该类改变了类变量,那读取的旧缓存的文件还能正确恢复吗,新添加的字段被恢复成默认值还是直接报InvalidClassException的异常?

那如果是通过fastJson的jsonString存储和恢复呢?因为这种方式是将对象编程键值对的json格式,不是严格意义上序列化,github的说明上也说了,只要是符合JavaBean规范的都可以,不用非要serialVerionUID。demo很简单就可以证明。

具体详细的解释可以参考:Java序列化

平时定义的bean都是json对应的,看样子不怎么符合JavaBean标准。而且如有有复杂对象的拷贝需求,fastJson的方法看起来是最方便最快的。

正好需求中碰到相册数据的深拷贝,用的是序列化的方法做的。想到能不能改成json解析的方法,然后就刚好遇到了个问题。

  1. 序列化方法实现:单个对象clone,列表要在外层循环调用clone方法
    // serializable object
    public static GalleryItem deepCloneGalleryItem(GalleryItem in) {
        try {
            long ss= System.currentTimeMillis();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(in);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            LogUtil.v("InLog", "success deepCloneGalleryItem= " + (System.currentTimeMillis() - ss)) ;
            return (GalleryItem) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
            LogUtil.e("InLog", "IOException deepCloneGalleryItem");
            return null;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            LogUtil.e("InLog", "ClassNotFoundException deepCloneGalleryItem");
            return null;
        }
    }

    @Override
    public void notifyPrepareDataList(List<GalleryItem> list) {
        for (GalleryItem item : list) {
            it = ListUtil.deepCloneGalleryItem(item);
        }
    }
  1. Json转化方法实现:单个对象clone或直接整个列表clone
    public static void cloneJson(GalleryItem in){
        long ss = System.currentTimeMillis();
        String json = JSON.toJSONString(in);
        GalleryItem item = JSON.parseObject(json, GalleryItem.class);
        LogUtil.v("InLog", "cloneJson cost " + (System.currentTimeMillis() - ss));
        LogUtil.v("InLog", "cloneJson in " + in.hashCode() + ",item is  " + item.hashCode());
    }

    public static void cloneJson(List<GalleryItem> in){
        long ss = System.currentTimeMillis();
        String json = JSON.toJSONString(in);
        List<GalleryItem> item = JSON.parseArray(json, GalleryItem.class);
        LogUtil.d("InLog", "cloneJson cost " + (System.currentTimeMillis() - ss));
    }
    
    @Override
    public void notifyPrepareDataList(List<GalleryItem> list) {
        ListUtil.cloneJson(list);
    }

该对象的以上两种方法,json转换的方法并没有更快。1000个对象时间差不多。

使用的fastJson是android版本:'com.alibaba:fastjson:1.1.51.android',因为GalleryItem有个long型字段复写get方法时返回了String,导致JSON.toJSONString(in);一直报错:

Error:
com.alibaba.fastjson.JSONException: write javaBean error
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:600)
at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:262)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:607)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:334)
..............................................
.....
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:526)
... 21 more

被这个问题困扰好久,app os:死前我都提示线索了,你怎么还没破案啊。
原因就是get方法返回型和定义的不一样了。所以这种在bean里直接改变返回型的做法不适合在fastJson里用。

    public long duration;
    public String getDuration() {
        try {
            return formatTimeWithMin(duration);
        } catch (NumberFormatException e) {
            return "0:00";
        }
    }

但是在使用新的版本compile com.alibaba:fastjson:1.1.67.android,以上不会出错。应该是修复了该问题,但是在JonsString解析成对象时还是会报类型转换的异常导致转换不成功。所以还是在使用时注意这种情况的转换。

image

附送其他使用注意事项fastjson使用过程中的坑

以及一个容易被忽视的原因分析。
JVM源码分析之不保证顺序的Class.getMethods

当然开源库在更新,新的版本会有不同的优化,注意差异。

相关文章

  • 20171122-fastJson、序列化、深拷贝

    fastJson过滤器: fastjson 过滤不需要的字段或者只要某些字段 工具组同学在做热修复时发现一种rob...

  • 深入JavaScript Day33 - 序列化实现深拷贝的缺点

    一、序列化实现深拷贝的缺点、手写深拷贝 1、借助序列化实现深拷贝,有哪些缺点? ①不能拷贝函数 ②不能拷贝Symb...

  • 关于Java对象拷贝深拷贝与浅拷贝的实现

    序列化方式实现深拷贝

  • 什么是浅拷贝和深拷贝?

    创建Java对象的方式包括new、反射、反序列化、拷贝,那么什么是拷贝呢?浅拷贝和深拷贝又有什么区别呢? 什么是拷...

  • 几个偏基础的面试题

    1、iOS本地数据存储都有哪几种方式? 2、深拷贝和浅拷贝的理解? 3、什么是序列化和反序列化,可以用来做什么?如...

  • java

    1.反射、clone、反序列化创建对象 ,深拷贝(复制原型中对象的内存copy)和浅拷贝 (复制原型的引用) cl...

  • Java List的深度拷贝方法

    为了了解真正的深拷贝是如何实现的,我终于在CSDN博客中找到了通过序列化实现List的深度拷贝的方法 首先简单介绍...

  • 手写深拷贝

    方案1.序列化反序列化 上面的代码b就是a的深拷贝当我们修改b里面的值的时候,a的值不会跟着变化。 1.1.缺点 ...

  • 对象深拷贝和浅拷贝

    浅拷贝 深拷贝 深拷贝的递归方法 深拷贝的JSON方法

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

网友评论

      本文标题:20171122-fastJson、序列化、深拷贝

      本文链接:https://www.haomeiwen.com/subject/enwxgxtx.html