湖畔镇

Java——Json&Gson

本文介绍Java中的Json相关类

Java的Json包

org.json包中

最重要的是JSONObjectJSONArray两个结构,对应JSON对象和JSON数组

JSONObject

JSONObject json = new JSONObject("{'name' : 'Alice', 'age' : 20}");
String name = json.getString("name");  
int age = json.getInt("age");  

JSON字符串获得JSONObject,从JSON对象中获得属性

//  一个空的对象
public JSONObject();

//  传入键值对
public JSONObject(Map copyFrom);

//  传入JSON字符串
public JSONObject(String json) throws JSONException;

//  传入一个Token
public JSONObject(JSONTokener readFrom) throws JSONException;

//  应该是从一个已有的对象里取得对应的键值对来形成一个新对象
public JSONObject(JSONObject copyFrom, String[] names) throws JSONException;

一组构造函数

JSONArray

JSONArray array = new JSONArray("[{'name' : 'Alice', 'age' : 20}, {'name' : 'Eric', 'age' : 15}]");  
for (int i = 0; i < array.length(); i++){  
    JSONObject json = array.getJSONObject(i).
    String name = json.getString("name");  
    int age = json.getInt("age");  
} 

从字符串获得JSONArray,遍历其中的JSONObject

public JSONArray() {
public JSONArray(Collection copyFrom);
public JSONArray(String json) throws JSONException;
public JSONArray(Object array) throws JSONException;
public JSONArray(JSONTokener readFrom) throws JSONException;

也有一组不同的构造函数

可以嵌套使用,通过getJSONArray()获得数组,遍历数组获得JSONObject

JSONStringer

用来快速构建JSON字符串

JSONStringer stringer = new JSONStringer();  
String str = stringer.object().key("name").value("Eric").key("age").value(20).endObject().toString();

JSONToken

JSONTokener方法获得一个对象,根据括号类型或引号决定是什么(JSONObjectJSONArray或字符串)

//  可以从文件中读取一个JSONObject
JSONObject obj = new JSONObject( new JSONTokener(java.io.Reader));

//  可以从文件中读取一个JSONArray
JSONArray obj = new JSONArray( new JSONTokener(java.io.Reader)); 

JSONWriter

用来输出JSON

PrintWriter out = new PrintWriter(System.out);  
new JSONWriter(out).object().key("name").value("Alice").endObject();  
out.flush();  
out.close();  

GSON

基本用法

Gson gson = new Gson();

//  基础类型
int i = gson.fromJson("100", int.class);
double d = gson.fromJson("99.99", double.class);
boolean b = gson.fromJson("true", boolean.class);
String s = gson.fromJson("Hello", String.class);

定义一个类

public class User {
    public String name;
    public int id;
}

解析

Gson gson = new Gson();
User user = gson.fromJson("{'name' : 'Alice', 'id' : 1}", User.class);

生成

User user = new User;
user.name = 'Eric';
user.id = 1;
Gson gson = new Gson();
String string = gson.toJson(user);

SerializedName

后台开发经常会用到下划线命名变量,这时需要使用@SerializedName来标记一下对应关系

{"name" : "Alice", "email_address" : "alice@example.com"}

这时的类应该是

public class User {
    public String name;

    @SerializedName("email_address")
    public String emailAddress;
}

另外可以提供备选名

@SerializedName("email_address", alternate = {"email"})
public String emailAddress;

对象数组

Gson gson = new Gson();
String string = "['Android', 'Java', 'PHP']";
String[] langs = gson.fromJson(string, String[].class);

因为泛型擦除机制,列表不能这样用,需要使用TypeToken

List<String> langs = gson.fromJson(string, new TypeToken<List<String>>(){}.getType());

引入泛型

泛型的引入可以减少无关的代码,很多时候后台返回的结果是这样的

{"code" : "0", "message" : "success", "data" : {}}

data中的东西可能不一样,但不需要每个都定义一个类,定义泛型类就好了

public class Result<T> {
    public int code;
    public String message;
    public T data;
}

返回的东西是个User就写Result<User>,是个List<User>就写Result<List<User>>

自定义

手动反序列化

String json = "{'name' : 'Alice', 'age' : 24}";
User user = new User();
JsonReader reader = new JsonReader(new StringReader(json));
reader.beginObject(); 
while (reader.hasNext()) {
    String s = reader.nextName();
    switch (s) {
        case "name":
            user.name = reader.nextString();
            break;
        case "age":
            user.age = reader.nextInt();
            break;
    }
}
reader.endObject();

自动方式最后也是通过JsonReader来实现的

手动序列化

JsonWriter writer = new JsonWriter(new OutputStreamWriter(System.out));
writer.beginObject().name("name").value("Alice").name("age").value(24).endObject();
writer.flush();

GsonBuilder

可以用来自定义Gson

Gson gson = new GsonBuilder().create();

Gson默认不输出null值,可以用serializeNulls()来配置

通过setDateFormat("yyyy-MM-dd")格式化日期

disableInnerClassSerialization()禁止序列化内部类

字段过滤

字段过滤是比较常用的技巧,在处理业务逻辑时可能需要在设置的POJO中加入一些字段,但显然在序列化的过程中是不需要的,并且如果序列化还可能带来一个问题就是循环引用

@Expose注解

这个注解必须和GsonBuilder结合使用,需要导出的加该注解,不需要的不加

public class Category {
    @Expose 
    public int id;

    @Expose 
    public String name;

    @Expose 
    public List<Category> children;

    public Category parent; 
}

序列化的方法也要改

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

基于版本

使用@Since@Until注解导出指定版本的字段,与setVersion()一起使用

class SinceUntilSample {

    //  版本不小于4时导出
    @Since(4)
    public String since;

    //  版本不大于5时导出
    @Until(5)
    public String until;
}

Gson gson = new GsonBuilder().setVersion(version).create();

基于访问修饰符

Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE).create();

基于策略

Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new ExclusionStrategy() {
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        if ("finalField".equals(f.getName())) {
            return true;
        }

        Expose expose = f.getAnnotation(Expose.class); 
        if (expose != null && expose.deserialize() == false) {     return true;
        }

        return false;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return (clazz == int.class || clazz == Integer.class);
    }
}).create();

终极:TypeAdapter

public abstract class TypeAdapter<T> {
    public abstract void write(JsonWriter out, T value) throws IOException;
    public abstract T read(JsonReader in) throws IOException;
    ......
}

这个类接管某种类型的序列化和反序列化

public class UserTypeAdapter extends TypeAdapter<User> {

    @Override
    public void write(JsonWriter out, User value) throws IOException {
        out.beginObject();
        out.name("name").value(value.name);
        out.name("age").value(value.age);
        out.endObject();
    }

    @Override
    public User read(JsonReader in) throws IOException {
        User user = new User();
        in.beginObject();
        while (in.hasNext()) {
            switch (in.nextName()) {
                case "name":
                    user.name = in.nextString();
                    break;
                case "age":
                    user.age = in.nextInt();
                    break;
            }
        }
        in.endObject();
        return user;
    }
}

Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserTypeAdapter()).create();

这个类的处理优先级最高,会覆盖之前的所有注解

class JsonDeserializer<T>() {
    @Override
    public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException;
}

class JsonSerializer<T>() {
    @Override
    public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
};

如果只想接管其中一个过程,则只需要实现上面的一个

Gson gson = new GsonBuilder().registerTypeAdapterFactory(new TypeAdapterFactory() {

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        ......
    }

}).create();

对应的工厂,获取对应typeTypeAdapter

@JsonAdapter(UserTypeAdapter.class)
public class User {
    ......
}

使用@JsonAdapter注解可以省去注册的代码

分享