`
bit1129
  • 浏览: 1067737 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

[Gson八]GsonBuilder序列化和反序列化选项enableComplexMapKeySerialization

 
阅读更多

enableComplexMapKeySerialization配置项的含义

 Gson在序列化Map时,默认情况下,是调用Key的toString方法得到它的JSON字符串的Key,对于简单类型和字符串类型,这没有问题,但是对于复杂数据对象,如果对象没有覆写toString方法,那么默认的toString方法将得到这个对象的Hash地址。

 

GsonBuilder用于为创建Gson对象设置配置选项,这些选项可以覆盖通过Gson gson = new Gson()创建的Gson对象,例如下面的例子代码:

 

不启用enableComplexMapKeySerialization并且不启动类型适配器(PointTypeAdapter)

 

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

class Point {
    private  int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}



public class Test {

    public static void main(String[]args) {

        Map<Point, String> map = new HashMap<Point, String>();
        Point p1 = new Point();
        p1.setX(10);
        p1.setY(10);
        map.put(p1, "Ten");

        Point p2 = new Point();
        p2.setX(20);
        p2.setY(20);
        map.put(p2, "Twenty");

        Gson gson  = new GsonBuilder().create();
        String str = gson.toJson(map);
        System.out.println(str);//{"test1.Point@5ba5ba75":"Ten","test1.Point@5d748654":"Twenty"}

        Type type = new TypeToken<Map<Point,String>>(){}.getType();

        map  = gson.fromJson(str, type);//java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING
    }
}

 代码输出 {"Point@6f92c766":"Twenty","Point@6406c7e":"Ten"},可见Key转换成字符串时,使用的Key.toString()方法(这里的Key是Point类型),这样转换结果基本是无法接受的,因为序列化出来的JSON串无法反序列化原来的Map集合。在上面的反序列化时,抛出异常因为Gson因为Point@6f92c766只是一个简单的字符串,无法转型为Point。
 

启用enableComplexMapKeySerialization配置项,但是不启用类型适配器

如果仅仅启用enableComplexMapKeySerialization配置项,但是不为Point类自定义类型适配器,那么这个Map将被序列化为JSON数组,数组的每个元素也是一个数组,这个数组的长度为2,第一个值为Key转换得到的JSON对象字符串,第二个值是Value对应的JSON字符串。如下代码所示:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

class Point {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}
public class Test {
    public static void main(String[] args) {
        Map<Point, String> map = new HashMap<Point, String>();
        Point p1 = new Point();
        p1.setX(10);
        p1.setY(10);
        map.put(p1, "Ten");

        Point p2 = new Point();
        p2.setX(20);
        p2.setY(20);
        map.put(p2, "Twenty");

        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.enableComplexMapKeySerialization();
        Gson gson = gsonBuilder.create();
        String str = gson.toJson(map);
        System.out.println(str); //[[{"x":10,"y":10},"Ten"],[{"x":20,"y":20},"Twenty"]]
        Type type = new TypeToken<Map<Point, String>>(){}.getType();
        map = gson.fromJson(str, type); //转换成功
    }

}
 

 

启用enableComplexMapKeySerialization配置项,并且启用类型适配器

 

 

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

class Point {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

class PointTypeAdapter extends TypeAdapter<Point> {

    @Override
    public void write(JsonWriter out, Point value) throws IOException {
        if (value == null) {
            out.nullValue();
        } else {
            out.value("(" + value.getX() + "," + value.getY() + ")");
        }
    }

    @Override
    public Point read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            return null;
        } else {
            String str = in.nextString(); 
            str = str.substring(1, str.length() - 1); //根据writer的格式,解析字符串
            String[] pair = str.split(",");
            Point p =  new Point();
            p.setX(Integer.parseInt(pair[0]));
            p.setY(Integer.parseInt(pair[1]));
            return p;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Map<Point, String> map = new HashMap<Point, String>();
        Point p1 = new Point();
        p1.setX(10);
        p1.setY(10);
        map.put(p1, "Ten");

        Point p2 = new Point();
        p2.setX(20);
        p2.setY(20);
        map.put(p2, "Twenty");

        Gson gson = new GsonBuilder().enableComplexMapKeySerialization().registerTypeAdapter(Point.class, new PointTypeAdapter()).create();
        String str = gson.toJson(map);
        System.out.println(str); //{"(10,10)":"Ten","(20,20)":"Twenty"}
        Type type = new TypeToken<Map<Point, String>>() {
        }.getType();
        map = gson.fromJson(str, type); //转换成功
    }

}

 

 

启用类型适配器,但不启用enableComplexMapKeySerialization

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

class Point {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

class PointTypeAdapter extends TypeAdapter<Point> {

    @Override
    public void write(JsonWriter out, Point value) throws IOException {
        if (value == null) {
            out.nullValue();
        } else {
            out.value("(" + value.getX() + "," + value.getY() + ")");
        }
    }

    @Override
    public Point read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            return null;
        } else {
            String str = in.nextString(); 
            str = str.substring(1, str.length() - 1); //根据writer的格式,解析字符串
            String[] pair = str.split(",");
            Point p =  new Point();
            p.setX(Integer.parseInt(pair[0]));
            p.setY(Integer.parseInt(pair[1]));
            return p;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Map<Point, String> map = new HashMap<Point, String>();
        Point p1 = new Point();
        p1.setX(10);
        p1.setY(10);
        map.put(p1, "Ten");

        Point p2 = new Point();
        p2.setX(20);
        p2.setY(20);
        map.put(p2, "Twenty");

        Gson gson = new GsonBuilder().registerTypeAdapter(Point.class, new PointTypeAdapter()).create();
        String str = gson.toJson(map);
        System.out.println(str); //{"Point@e0cc23":"Twenty","Point@76ab2f":"Ten"}
        Type type = new TypeToken<Map<Point, String>>() {
        }.getType();
        map = gson.fromJson(str, type); //转换成功
    }

}

 

 上面的代码如果仅仅注册PointTypeAdapter而不调用enableComplexMapKeySerialization,序列化的结果仍然是{"Point@e0cc23":"Twenty","Point@76ab2f":"Ten"}

 

总结

 1.如果在序列化Map类型的对象时,如果Key是复杂数据类型(不是基本数据类型或者String,即自定义POJO),此时就要使用enableComplexMapKeySerialization配置选项,否则Gson默认是以Key.toString()作为JSON字符串对应的Key

 2.在实际中,麻烦的是根据JSON字符串的结构定义对应的POJO,如果JSON串中key是JSON对象格式,可以考虑使用使用Map,并且把Key定义为复杂类型,然后同时启用enableComplexMapKeySerialization选项和注册TypeAdapter

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    Gson 枚举类型的统一序列化/反序列化处理

    然而,在使用Gson库进行JSON序列化和反序列化时,枚举处理默认方式可能无法满足所有需求。本篇文章将详细探讨如何通过自定义Gson适配器实现枚举类型的统一序列化和反序列化处理,无需预先定义枚举,也无需修改Gson...

    Gson解析之自定义序列化和反序列化

    本篇文章将深入探讨如何在使用Gson时进行自定义的序列化和反序列化,以及在遇到后端返回的数据类型与预期不符时的处理策略。 ### Gson自定义序列化 自定义序列化主要是为了在转换Java对象为JSON时,根据特定需求...

    com.google.gson.Gson 2.8.1 2.8.2 jar包 gson

    1. **类型安全的序列化与反序列化**:Gson允许开发者通过`Gson.toJson()`和`Gson.fromJson()`方法轻松地将Java对象转换为JSON字符串,反之亦然。这个过程是类型安全的,因为Gson会根据对象的类信息自动处理数据类型...

    protostuff fastjson gson 高性能序列化jar包

    这三个jar包——`fastjson-1.2.35.jar`、`gson-2.8.1.jar`和`protostuff`,分别包含了对应库的实现,可以在Java项目中引入这些库来实现高效的序列化和反序列化功能。记得在使用前,先根据项目的需求和兼容性评估哪个...

    gson源码与文档,集成多枚举类型统一序列化/反序列化处理

    本文将深入探讨如何利用Gson库进行多枚举类型的统一序列化和反序列化处理,以此避免为每个枚举类型单独创建Adapter。 首先,我们需要了解Gson的基本用法。Gson的核心类是`Gson`,它提供了`toJson()`和`fromJson()`...

    kotlin gson反序列化默认值失效深入讲解

    Gson反序列化是一种常用的数据序列化和反序列化技术,它广泛应用于 Android 开发、Web 开发等领域。然而,在使用 Gson 进行反序列化时,可能会出现默认值失效的问题,本文将深入讲解 Gson 反序列化默认值失效的原因...

    一个Java序列化反序列化库,用于将Java对象转换为JSON和返回JSON.zip

    总之,Java序列化和反序列化库对于开发人员来说是不可或缺的工具,Gson作为其中的一个优秀库,提供了简单而强大的功能,使得Java对象与JSON之间的转换变得轻松快捷。正确理解和使用这类库,可以极大地提高开发效率和...

    gson-2.3.1的jar包含源码和说明文档

    2. **示例代码**:文档中通常包含许多示例代码,展示如何使用Gson进行基本操作,如创建Gson对象、序列化和反序列化Java对象、处理特殊类型的转换等。 3. **异常处理**:文档还会解释在使用Gson过程中可能遇到的异常...

    google gson包json格式化

    Gson可以轻松地处理Java集合(如List、Set、Map)和数组的序列化和反序列化。 6. **日期格式化** 可以通过自定义`JsonSerializer`和`JsonDeserializer`来处理日期格式。 7. **自定义异常处理** 可以捕获并...

    gson最新源码

    3. **TypeAdapter和JsonSerializer/JsonDeserializer**: 这些是Gson的自定义序列化和反序列化机制。当你需要对特定类型进行特殊处理时,可以创建自定义的适配器。例如,如果你有一个复杂的日期对象,你可以编写一个`...

    om.google.gson.Gson Gson maven依赖

    10. **GsonBuilder**:`GsonBuilder`提供了一种构建自定义Gson实例的方式,可以设置各种序列化和反序列化的选项。 在实际开发中,Gson库的灵活性和易用性使其成为处理JSON数据的首选工具。无论是在Android开发还是...

    gson源码.rar

    4. **ReflectiveTypeAdapterFactory**: 这是Gson内部的一个重要适配器,负责使用反射机制来序列化和反序列化Java对象的字段。 5. **JsonElement**: JSON数据的抽象表示,包括JsonObject、JsonArray、JsonPrimitive...

    shiro反序列化漏洞检测工具,含链接教程

    3. 使用安全的反序列化库:例如,使用Google的Gson库时启用`GsonBuilder`的`disableCircularReferences()`和`enableComplexMapKeySerialization()`选项。 4. 自定义反序列化逻辑:对于必须处理的序列化数据,自定义...

    Gson实例源码下载

    在本实例中,我们将深入探讨Gson库的使用方法,包括序列化(将Java对象转换为JSON字符串)和反序列化(将JSON字符串转换回Java对象)。 首先,我们需要在项目中引入Gson库。如果你使用的是Maven,可以在pom.xml文件...

    gson转义字符

    在Java开发过程中,经常需要对数据进行序列化与反序列化操作,而Gson作为一款非常流行的库,被广泛应用于这些场景中。然而,在实际应用过程中可能会遇到一些问题,比如某些特殊字符(如HTML标签、Unicode字符等)会...

    Google gson

    不过,需要注意的是,由于Gson将所有非`transient`和非`static`字段默认都纳入序列化和反序列化的范围,因此对于包含敏感信息的字段,可能需要额外的措施来保护。 总结来说,Google Gson是一个功能强大、易用且灵活...

    java的gson-2.2.1.jar包

    2. **灵活性**: Gson支持自定义序列化和反序列化的逻辑,可以通过注解或自定义TypeAdapter实现。 3. **性能**: Gson设计高效,执行速度快,内存占用低,适用于大量数据处理的场景。 4. **易用性**: Gson的API简单...

    google-gson

    10. **安全性**: 在 Android 开发中,Gson 还可以帮助你在序列化和反序列化过程中防止跨站脚本攻击(XSS),通过使用 `GsonBuilder.enableComplexMapKeySerialization()` 方法。 总之,"google-gson" 是一个强大的...

    gson-2.8.6.zip

    6. **GsonBuilder**:提供了一种构建自定义Gson实例的方式,可以通过`GsonBuilder`配置序列化和反序列化的行为,例如忽略未知字段、设置日期格式等。 7. **流式API(Streaming API)**:Gson提供了一个低级别的流式...

    Gson的三个jar包

    8. **序列化策略**:Gson提供了两种序列化策略:`ExclusionStrategies`允许你在序列化和反序列化时排除某些字段,而`FieldNamingPolicy`则可以改变字段名的映射规则。 在使用Gson的jar包时,你需要确保引入了正确的...

Global site tag (gtag.js) - Google Analytics