• Gson 问题汇总


    使用Gson

    gson是google推出的json解析框架,相较于其他json解析框架,它速度更快也更安全(网上有很多资料,这里就不赘述了),在maven项目中使用gson,只需要引入以下配置即可,这里使用的2.8.5版本

      
       com.google.code.gson
          gson
          2.8.5
     
    
    • 1
    • 2
    • 3
    • 4
    • 5

    springboot中指定Gson为默认消息转换器

    在springBoot中注入定义的HttpMessageConverter 即可(若使用的其他json框架,注入相应的HttpMessageConverter),例如:

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Bean
        public HttpMessageConverter GsonHttpMessageConverter() {
            GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
            gsonHttpMessageConverter.setGson(new Gson());//放入Gson实例
            return gsonHttpMessageConverter;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    自定义Gson实例

    在Gson使用过程中,可能遇到多种情况,例如:

    • 需要设定日期类型的格式
    • 处理特殊格式数据
    • 在解析serialVersionUID字段时发生 class declares multiple JSON fields named serialVersionUid
    • json字符串中的int类型,转换后变成了double类型

    解决方法

    设定日期类型的格式

    第一种方式:
    使用JsonDeserializer来指定反序列化(解析)方式,与此对应的还有JsonSerializer接口,用来指定对象序列化方式:

    //设定Date类型的反序列化(解析)规则
       private static final com.google.gson.JsonDeserializer<Date> deser = new com.google.gson.JsonDeserializer<Date>() {
                @Override
                public Date deserialize(JsonElement json, Type typeOfT,
                                        JsonDeserializationContext context) throws JsonParseException {
                    String date = json.getAsString();
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                    format.setTimeZone(TimeZone.getTimeZone("GMT"));
                    try {
                        return format.parse(date);
                    } catch (ParseException exp) {
                        System.err.println(exp.getMessage());
                        return null;
                    }
                }
            };
      private final static Gson INSTANCE = new GsonBuilder().serializeNulls().registerTypeAdapter(Date.class, deser).create();//制定Date类型的转换器
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    第二种方式:

       private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
       private final static Gson INSTANCE = new GsonBuilder().serializeNulls().setDateFormat(DATE_FORMAT).create();//此规则 将用于序列化与反序列化Date对象,如果多次指定此规则,将以最后一次为准
    
    • 1
    • 2

    第二种方式=JsonDeserializer+JsonSerializer
    如果项目中已经约定好使用统一的日期格式,使用第二种方式更简便易读

    处理特殊格式数据

    在某场景中,原本是double类型的数据,在上百条数据中,有几条数据因为数据为空,我接收到是"-“,一转换就报类型无法转换错误(因为是爬取数据),我只能自己想办法把”-"转为——(double)0

        @Test
        void contextLoads() {
            String dataJson = "{\"number\" : 30.2, \"amount\" : \"-\"}";
            Gson gson = GsonUtils.getSingleton();
            Map map = gson.fromJson(dataJson, Map.class);
            System.out.println(map);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解决:

            public static final TypeAdapter<Number> NumberFormat = new TypeAdapter<Number>() {
                @Override
                public Number read(JsonReader in) throws IOException {
    
                    if (in.peek() == JsonToken.NULL) {
                        in.nextNull();
                        return 0;
                    }
                    try {
                        double i = in.nextDouble();
                        return  i;
                    } catch (NumberFormatException e) {
                        //如果报数字格式化异常,判断是否为目标字符串
                        if (e.getMessage().contains("-")){
                            Class<JsonReader> jsonReaderClass = JsonReader.class;
                            try {
                                Field peekedString = jsonReaderClass.getDeclaredField("peekedString");
                                peekedString.setAccessible(true);
                                peekedString.set(in,"0.0");//通过反射更改了json字符串中原"-"为0.0
                                double i = in.nextDouble();//更改值后重新计算
                                return  i;
                            } catch (NoSuchFieldException ex) {
                                ex.printStackTrace();
                            } catch (IllegalAccessException ex) {
                                ex.printStackTrace();
                            }
                            return  0.0;
                        }else {
                            throw new JsonSyntaxException(e);
                        }
                    }
                }
    
                @Override
                public void write(JsonWriter out, Number value) throws IOException {
                    out.value(value);
                }
            };
    
    
      private final static Gson INSTANCE = new GsonBuilder().serializeNulls()
      										 .disableHtmlEscaping()//默认情况下,Gson会转义HTML字符,例如<>等。使用此选项将 Gson配置为直接传递HTML字符
      										 .registerTypeAdapter(Date.class, deser)
      										 .registerTypeAdapter(Double.class, NumberFormat)
                   							 .registerTypeAdapter(double.class, NumberFormat)
                   							 .create();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    由于registerTypeAdapter只注册指定的类型,不会注册相关类型,所以注册Double时,也需要注册double类型,贴出registerTypeAdapter方法源码以及注释:

     /**
       * Configures Gson for custom serialization or deserialization. This method combines the
       * registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a
       * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
       * all the required interfaces for custom serialization with Gson. If a type adapter was
       * previously registered for the specified {@code type}, it is overwritten.
       *
       * 

    This registers the type specified and no other types: you must manually register related * types! For example, applications registering {@code boolean.class} should also register {@code * Boolean.class}. * * @param type the type definition for the type adapter being registered * @param typeAdapter This object must implement at least one of the {@link TypeAdapter}, * {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ @SuppressWarnings({"unchecked", "rawtypes"}) public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) { $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?> || typeAdapter instanceof TypeAdapter<?>); if (typeAdapter instanceof InstanceCreator<?>) { instanceCreators.put(type, (InstanceCreator) typeAdapter); } if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) { TypeToken<?> typeToken = TypeToken.get(type); factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter)); } if (typeAdapter instanceof TypeAdapter<?>) { factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter)); } return this; }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    大家不一定会遇到一摸一样的场景,这里只是提供一个思路

    解析serialVersionUID字段报错

    在项目中,出现:class declares multiple JSON fields named serialVersionUid异常
    解决:

      private static final List<String> EXCLUDE = new ArrayList<String>() {{
                add("serialVersionUID");
            }};
     private final static Gson INSTANCE = new GsonBuilder().serializeNulls()
    									 .setExclusionStrategies(new ExclusionStrategy() {
    									
    									                    @Override
    									                    public boolean shouldSkipField(FieldAttributes f) {
    									                        boolean exclude = false;
    									                        try {
    									                            exclude = EXCLUDE.contains(f.getName());
    									                        } catch (Exception ignore) {
    									                        }
    									                        return exclude;
    									                    }
    									
    									                    @Override
    									                    public boolean shouldSkipClass(Class<?> aClass) {
    									                        return false;
    									                    }
    									                })//制定排除策略
    									     .disableHtmlEscaping()//默认情况下,Gson会转义HTML字符,例如<>等。使用此选项将 Gson配置为直接传递HTML字符
      										 .registerTypeAdapter(Date.class, deser)
      										 .registerTypeAdapter(Double.class, NumberFormat)
                   							 .registerTypeAdapter(double.class, NumberFormat)
                   							 .create();
                    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    int类型,转换后变成了double类型

    参考
    Error: Class declares multiple JSON fields named serialVersionUid

  • 相关阅读:
    运维自动导出业务容器Java堆栈错误日志脚本
    微服务治理之道:构建可伸缩和高可用的系统
    【AIGC】开源声音克隆GPT-SoVITS
    【torch.nn.init】初始化参数方法解读
    vue3+vite 学习 创建项目
    大家在日常工作中有哪些非常好用的在线办公软件?
    小林coding网站---mysql基础-MySQL索引的数据结构和算法
    Float/Double内存结构分析,取值范围、有效位数与内存结构的关系详解(有效位数和取值范围如何得出?)
    C语言-文件读写fscanf函数
    详细介绍 React 中如何使用 redux
  • 原文地址:https://blog.csdn.net/qq_42982191/article/details/117034514