美文网首页Android大法好
Gson 自定义排除策略

Gson 自定义排除策略

作者: Walkud | 来源:发表于2016-04-07 19:54 被阅读1184次

    结合业务进行学习Gson排除策略,业务如下:

    一个类有6个属性 ,用Gson进行序列化和反序列化,其中有1个属性需要排除。

    使用自定义之前,有必要了解一下@Expose注解

    源码

    package com.google.gson.annotations;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Expose {
      
      /**
       * 是否序列化
       */
      public boolean serialize() default true;
    
      /**
       * 是否反序列化
       */
      public boolean deserialize() default true;
    }
    

    Expose注解有2个属性

    serialize 序列化(默认为true)

    deserialize 反序列化(默认为true)

    业务实体类

        public class ExposeUser {
    
            public static int expStatic;//Gson默认情况会排除带有static关键字属性
    
            @Expose
            public String name;//姓名
            @Expose
            public int age;//年龄
            @Expose
            public String sex;//性别
            @Expose
            public int height;//身高
            @Expose
            public float weight;//体重
            public boolean isLogin;//是否登录
    
            @Override
            public String toString() {
                return "{\"expStatic\":\"" + expStatic
                        + "\",\"name\":\"" + name
                        + "\",\"age\":\"" + age
                        + "\",\"sex\":\"" + sex
                        + "\",\"height\":\"" + height
                        + "\",\"weight\":\"" + weight
                        + "\",\"isLogin\":\"" + isLogin + "\"}";
            }
        }
    
    

    使用该注解时必须在构建Gson对象时调用excludeFieldsWithoutExposeAnnotation此方法生效,否则不会生效。

    针对业务需求使用@Expose注解也能达到需求,但有个问题是,如果实体类包含多个属性(比如15个需要序列化的属性),那在代码上就会不优雅。

    public static void main(String[] args) {
    
            Gson gson = new GsonBuilder()
                    .excludeFieldsWithoutExposeAnnotation()//只序列化和反序列化带Expose注解属性
                    .create();
    
            ExposeUser eu = new ExposeUser();
            eu.name = "Gson";
            eu.age = 22;
            eu.sex = "男";
            eu.height = 175;
            eu.weight = 66.5f;
            eu.isLogin = true;
    
            String json = gson.toJson(eu);
    
            System.out.println(json);//输出结果:{"name":"Gson","age":22,"sex":"男","height":175,"weight":66.5}
    
            json = "{\"expStatic\":\"5\",\"name\":\"Gson\",\"age\":22,\"sex\":\"男\",\"height\":175,\"weight\":66.5,\"isLogin\":true}";
    
            ExposeUser deserEu = gson.fromJson(json, ExposeUser.class);
            System.out.println(deserEu.toString());//输出结果:{"expStatic":"0","name":"Gson","age":"22","sex":"男","height":"175","weight":"66.5","isLogin":"false"}
    
        }         
        
    

    在上段代码中输出结果可以看出,带有static关键字的属性会自动排除,不进行序列化和反序列化。

    自定义排除策略

    基于相同业务,但是实体类会在注解上有变化

        public class MExposeUser {
    
            public static int expStatic;//Gson默认情况会排除带有static关键字属性
    
            public String name;//姓名
            public int age;//年龄
            public String sex;//性别
            public int height;//身高
            public float weight;//体重
            @MyExclus
            public boolean isLogin;//是否登录
    
            @Override
            public String toString() {
                return "{\"expStatic\":\"" + expStatic
                        + "\",\"name\":\"" + name
                        + "\",\"age\":\"" + age
                        + "\",\"sex\":\"" + sex
                        + "\",\"height\":\"" + height
                        + "\",\"weight\":\"" + weight
                        + "\",\"isLogin\":\"" + isLogin + "\"}";
            }
        }
    
    

    Gson提供ExclusionStrategy接口,通过类名就知道作用

    public interface ExclusionStrategy {
    
      /**
       * @param f the field object that is under test
       * @return true if the field should be ignored; otherwise false
       */
      public boolean shouldSkipField(FieldAttributes f);
    
      /**
       * @param clazz the class object that is under test
       * @return true if the class should be ignored; otherwise false
       */
      public boolean shouldSkipClass(Class<?> clazz);
    }
    
    

    先来看看如何实现的

    
        /**
         * 自定义排除策略
         */
        public class MyExclusionStrategy implements ExclusionStrategy {
    
            /**
             * 需要跳过的属性
             *
             * @param f
             * @return
             */
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                //如果属性带有MyExclus 注解,则排除
                return f.getAnnotation(MyExclus.class) != null;
            }
    
            /**
             * 需要跳过的类
             *
             * @param clazz
             * @return
             */
            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        }
    
    

    从业务逻辑来讲需要排除的是某个属性属性,所以实现shouldSkipField方法,方法中判断如果当前属性带有MyExclus注解则排除。如何需要排除类,则可以实现shouldSkipClass方法。

    MyExclus注解是自定义的,在需要排除的属性上添加此注解

    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface MyExclus {
    }
    
    
    

    万事具备,只欠东风,在构建Gson对象的时候,将自定义的排除策略调用setExclusionStrategies方法设置一下就可以了。

    
    public static void main(String[] args) {
    
            Gson gson = new GsonBuilder()
                    .setExclusionStrategies(new MyExclusionStrategy())
                    .create();
    
            MExposeUser eu = new MExposeUser();
            eu.name = "Gson";
            eu.age = 22;
            eu.sex = "男";
            eu.height = 175;
            eu.weight = 66.5f;
            eu.isLogin = true;
    
            String json = gson.toJson(eu);
    
    
            System.out.println(json);
    
            json = "{\"expStatic\":\"5\",\"name\":\"Gson\",\"age\":22,\"sex\":\"男\",\"height\":175,\"weight\":66.5,\"isLogin\":true}";
    
            MExposeUser deserEu = gson.fromJson(json, MExposeUser.class);
            System.out.println(deserEu.toString());
        }
        
    

    最后了解下shouldSkipClass方法如何实现

    
    Gson gson = new GsonBuilder()
            .addSerializationExclusionStrategy(new ExclusionStrategy() {
                @Override
                public boolean shouldSkipField(FieldAttributes f) {
                    return false;
                }
                @Override
                public boolean shouldSkipClass(Class<?> clazz) {
                    // 排除指定的类
                    return Integer.class == clazz;
                }
            })
            .create();
    
    

    如果将身高声明为Integer的话,则会被排除在外

    总结一下

    希望通过写博客来提升自己的技术与语言组织水平,有什么写错的地方,还请大家多多反馈交流

    以上2种解决方案可以根据业务的实际情况选择适合的方案。

    GitHub源码

    记住:没有什么最好的,只有最适合的

    相关文章

      网友评论

      • Zack_zhou:找这篇文章找的好苦,我也是有很多字段,只有一个不需要,用@Expose太不优雅了,网上太多的文章稀里糊涂的都只说了@Expose,谢谢楼主!
        Walkud: @Zack_zhou 很高兴能帮到你😊

      本文标题:Gson 自定义排除策略

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