码字不易,请大佬们点点关注,谢谢~
一、TypeAdapter接口概述
1.1 TypeAdapter在Gson中的核心地位
在Android开发中,Gson作为主流的JSON处理框架,其核心功能之一是实现Java对象与JSON数据之间的相互转换。而TypeAdapter接口则是这一转换过程的核心抽象,它定义了序列化和反序列化的基本操作,为开发者提供了高度定制化的数据转换能力。
TypeAdapter是Gson 2.0版本引入的一个抽象类,相比早期使用的JsonSerializer和JsonDeserializer接口,TypeAdapter提供了更高效、更统一的API,避免了中间Tree模型的使用,从而提高了性能。
1.2 TypeAdapter接口的定义
TypeAdapter接口的定义如下:
public abstract class TypeAdapter<T> {
// 将Java对象序列化为JSON
public abstract void write(JsonWriter out, T value) throws IOException;
// 将JSON反序列化为Java对象
public abstract T read(JsonReader in) throws IOException;
// 以下是一些默认实现的便捷方法
// 将Java对象转换为JSON字符串
public final String toJson(T value) throws JsonIOException {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = newJsonWriter(stringWriter);
try {
write(jsonWriter, value);
jsonWriter.close();
return stringWriter.toString();
} catch (IOException e) {
throw new JsonIOException(e);
}
}
// 从JSON字符串解析为Java对象
public final T fromJson(String json) throws JsonSyntaxException {
StringReader stringReader = new StringReader(json);
return fromJson(stringReader);
}
// 从Reader解析为Java对象
public final T fromJson(Reader reader) throws JsonIOException, JsonSyntaxException {
JsonReader jsonReader = newJsonReader(reader);
return read(jsonReader);
}
// 创建JsonWriter实例
protected JsonWriter newJsonWriter(Writer writer) {
return new JsonWriter(writer);
}
// 创建JsonReader实例
protected JsonReader newJsonReader(Reader reader) {
return new JsonReader(reader);
}
}
1.3 TypeAdapter与其他序列化接口的关系
在Gson中,除了TypeAdapter接口外,还有JsonSerializer和JsonDeserializer接口用于处理序列化和反序列化。它们之间的关系如下:
- JsonSerializer和JsonDeserializer:这是Gson早期提供的接口,分别用于处理序列化和反序列化。它们的实现需要处理JsonElement中间对象,性能相对较低。
- TypeAdapter:是Gson 2.0引入的更高效的接口,直接操作JsonWriter和JsonReader,避免了中间对象的创建,提高了性能。
- TypeAdapterFactory:用于创建TypeAdapter的工厂接口,可以根据类型动态提供适配器。
Gson内部会将JsonSerializer和JsonDeserializer封装为TypeAdapter,以统一处理流程:
// TreeTypeAdapter类 - 用于封装JsonSerializer和JsonDeserializer
public final class TreeTypeAdapter<T> extends TypeAdapter<T> {
private final JsonSerializer<T> serializer;
private final JsonDeserializer<T> deserializer;
private final Gson gson;
private final TypeToken<T> typeToken;
private final TypeAdapterFactory skipPast;
private TypeAdapter<T> delegate; // 延迟初始化的委托适配器
// 构造函数
public TreeTypeAdapter(JsonSerializer<T> serializer,
JsonDeserializer<T> deserializer,
Gson gson,
TypeToken<T> typeToken,
TypeAdapterFactory skipPast) {
this.serializer = serializer;
this.deserializer = deserializer;
this.gson = gson;
this.typeToken = typeToken;
this.skipPast = skipPast;
}
// 实现TypeAdapter的write方法
@Override public void write(JsonWriter out, T value) throws IOException {
if (serializer == null) {
// 如果没有提供序列化器,使用委托适配器
delegate().write(out, value);
return;
}
if (value == null) {
out.nullValue();
return;
}
// 使用JsonSerializer将对象转换为JsonElement
JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext());
// 将JsonElement写入JsonWriter
Streams.write(tree, out);
}
// 实现TypeAdapter的read方法
@Override public T read(JsonReader in) throws IOException {
if (deserializer == null) {
// 如果没有提供反序列化器,使用委托适配器
return delegate().read(in);
}
// 从JsonReader读取JsonElement
JsonElement jsonTree = Streams.parse(in);
if (jsonTree.isJsonNull()) {
return null;
}
// 使用JsonDeserializer将JsonElement转换为对象
return deserializer.deserialize(jsonTree, typeToken.getType(), gson.deserializationContext());
}
// 获取委托适配器
private TypeAdapter<T> delegate() {
TypeAdapter<T> d = delegate;
return d != null
? d
: (delegate = gson.getDelegateAdapter(skipPast, typeToken));
}
}
二、核心方法write的原理
2.1 write方法的定义与作用
write方法是TypeAdapter接口中定义的用于将Java对象序列化为JSON的核心方法。其定义如下:
public abstract void write(JsonWriter out, T value) throws IOException;
该方法接收两个参数:
JsonWriter out:用于写入JSON数据的写入器T value:待序列化的Java对象
2.2 write方法的基本实现流程
在自定义TypeAdapter时,实现write方法通常需要遵循以下步骤:
- 处理null值:首先检查对象是否为null,如果为null,调用
out.nullValue()方法写入null值。 - 开始写入JSON结构:根据对象类型,调用
out.beginObject()开始写入对象,或调用out.beginArray()开始写入数组。 - 写入对象属性或数组元素:遍历对象的属性或数组的元素,调用相应的
out.name()和out.value()方法写入属性名和值。 - 结束JSON结构:调用
out.endObject()或out.endArray()结束对象或数组的写入。
2.3 源码级实现分析
下面通过一个具体的例子来分析write方法的实现原理。假设我们有一个简单的User类:
class User {
private String name;
private int age;
private boolean isAdmin;
// 构造方法和getter/setter省略
}
我们可以为其创建一个自定义的TypeAdapter:
class UserTypeAdapter extends TypeAdapter<User> {
@Override
public void write(JsonWriter out, User value) throws IOException {
// 处理null值
if (value == null) {
out.nullValue();
return;
}
// 开始写入JSON对象
out.beginObject();
// 写入name属性
out.name("name");
out.value(value.getName());
// 写入age属性
out.name("age");
out.value(value.getAge());
// 写入isAdmin属性
out.name("isAdmin");
out.value(value.isAdmin());
// 结束JSON对象
out.endObject();
}
// read方法实现省略
}
Gson内部在序列化时会调用这个write方法。让我们深入分析JsonWriter的关键方法实现:
public final class JsonWriter {
// 写入null值
public JsonWriter nullValue() throws IOException {
if (closed) throw new IOException("JsonWriter is closed");
beforeValue();
out.write("null");
return this;
}
// 开始写入JSON对象
public JsonWriter beginObject() throws IOException {
if (closed) throw new IOException("JsonWriter is closed");
writeDeferredName();
return open(JsonScope.EMPTY_OBJECT, "{");
}
// 写入属性名
public JsonWriter name(String name) throws IOException {
if (name == null) throw new NullPointerException("name == null");
if (closed) throw new IOException("JsonWriter is closed");
writeDeferredName();
return string(name);
}
// 写入字符串值
public JsonWriter value(String value) throws IOException {
if (value == null) {
return nullValue();
}
beforeValue();
string(value);
return this;
}
// 写入整数值
public JsonWriter value(long value) throws IOException {
if (closed) throw new IOException("JsonWriter is closed");
beforeValue();
out.write(Long.toString(value));
return this;
}
// 写入布尔值
public JsonWriter value(boolean value) throws IOException {
if (closed) throw new IOException("JsonWriter is closed");
beforeValue();
out.write(value ? "true" : "false");
return this;
}
// 结束写入JSON对象
public JsonWriter endObject() throws IOException {
return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, "}");
}
// 内部方法:写入字符串
private void string(String value) throws IOException {
out.write('"');
// 转义特殊字符
String escaped = stringPool.get(value);
if (escaped == null) {
escaped = JsonEscaper.escape(value);
stringPool.put(value, escaped);
}
out.write(escaped);
out.write('"');
}
}
2.4 处理嵌套对象和集合
当对象包含嵌套对象或集合时,write方法需要递归处理这些嵌套结构。例如,假设User类包含一个Address对象和一个爱好列表:
class User {
private String name;
private Address address;
private List<String> hobbies;
// 构造方法和getter/setter省略
}
class Address {
private String street;
private String city;
// 构造方法和getter/setter省略
}
对应的TypeAdapter实现如下:
class UserTypeAdapter extends TypeAdapter<User> {
private final TypeAdapter<Address> addressAdapter;
private final TypeAdapter<String> stringAdapter;
public UserTypeAdapter(Gson gson) {
// 获取Address和String的适配器
addressAdapter = gson.getAdapter(Address.class);
stringAdapter = gson.getAdapter(String.class);
}
@Override
public void write(JsonWriter out, User value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginObject();
// 写入name
out.name("name");
stringAdapter.write(out, value.getName());
// 写入address
out.name("address");
addressAdapter.write(out, value.getAddress());
// 写入hobbies
out.name("hobbies");
out.beginArray();
for (String hobby : value.getHobbies()) {
stringAdapter.write(out, hobby);
}
out.endArray();
out.endObject();
}
// read方法省略
}
在这个例子中,我们通过Gson获取了Address和String的适配器,并在写入嵌套对象和集合时调用它们的write方法,实现了递归处理。
三、核心方法read的原理
3.1 read方法的定义与作用
read方法是TypeAdapter接口中定义的用于将JSON数据反序列化为Java对象的核心方法。其定义如下:
public abstract T read(JsonReader in) throws IOException;
该方法接收一个参数:
JsonReader in:用于读取JSON数据的读取器
方法返回反序列化后的Java对象。
3.2 read方法的基本实现流程
在自定义TypeAdapter时,实现read方法通常需要遵循以下步骤:
- 检查JSON类型:首先检查当前JSON元素的类型(如对象、数组、字符串等)。
- 根据类型解析数据:根据JSON元素的类型,调用相应的读取方法(如
in.beginObject()、in.nextString()等)。 - 构建Java对象:将读取的数据转换为Java对象的属性值,并构建最终的Java对象。
- 返回结果:返回构建好的Java对象。
3.3 源码级实现分析
继续使用上面的User类示例,实现其read方法:
class UserTypeAdapter extends TypeAdapter<User> {
@Override
public User read(JsonReader in) throws IOException {
// 处理null值
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// 创建User对象
User user = new User();
// 开始解析JSON对象
in.beginObject();
while (in.hasNext()) {
// 读取属性名
String name = in.nextName();
// 根据属性名处理不同的属性
switch (name) {
case "name":
user.setName(in.nextString());
break;
case "age":
user.setAge(in.nextInt());
break;
case "isAdmin":
user.setAdmin(in.nextBoolean());
break;
default:
// 跳过未知属性
in.skipValue();
break;
}
}
// 结束解析JSON对象
in.endObject();
return user;
}
// write方法实现省略
}
让我们深入分析JsonReader的关键方法实现:
public final class JsonReader {
// 查看下一个JSON元素的类型
public JsonToken peek() throws IOException {
if (closed) throw new IllegalStateException("JsonReader is closed");
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
peeked = p;
}
return getToken(p);
}
// 读取null值
public void nextNull() throws IOException {
if (peek() != JsonToken.NULL) {
throw new IllegalStateException("Expected null but was " + peek() + locationString());
}
consumeValue();
pathIndices[stackSize - 1]++;
}
// 开始解析JSON对象
public void beginObject() throws IOException {
if (peek() != JsonToken.BEGIN_OBJECT) {
throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString());
}
int p = stack[stackSize - 1];
if (p == SCOPE_EMPTY_ARRAY) {
stack[stackSize - 1] = SCOPE_NONEMPTY_ARRAY;
} else if (p == SCOPE_EMPTY_OBJECT || p == SCOPE_DANGLING_NAME) {
stack[stackSize - 1] = SCOPE_NONEMPTY_OBJECT;
} else {
throw new IllegalStateException("Nesting problem.");
}
stack[stackSize++] = SCOPE_EMPTY_OBJECT;
pathNames[stackSize - 1] = null;
pathIndices[stackSize - 1] = 0;
consumeValue();
}
// 读取下一个属性名
public String nextName() throws IOException {
if (peek() != JsonToken.NAME) {
throw new IllegalStateException("Expected a name but was " + peek() + locationString());
}
String result = readString();
stack[stackSize - 1] = SCOPE_DANGLING_NAME;
pathNames[stackSize - 1] = result;
pathIndices[stackSize - 1] = 0;
return result;
}
// 读取下一个字符串值
public String nextString() throws IOException {
JsonToken token = peek();
if (token == JsonToken.STRING || token == JsonToken.NUMBER) {
return readString();
}
if (token == JsonToken.NULL) {
nextNull();
return null;
}
if (token == JsonToken.BOOLEAN) {
return Boolean.toString(nextBoolean());
}
throw new IllegalStateException("Expected a string but was " + token + locationString());
}
// 读取下一个整数值
public int nextInt() throws IOException {
JsonToken token = peek();
if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
throw new IllegalStateException("Expected NUMBER but was " + token + locationString());
}
String value = readString();
try {
int result = Integer.parseInt(value);
if (value.equals(Integer.toString(result))) {
pathIndices[stackSize - 1]++;
return result;
}
} catch (NumberFormatException e) {
// 处理数字格式异常
}
throw new NumberFormatException("Expected an int but was " + value + locationString());
}
// 结束解析JSON对象
public void endObject() throws IOException {
if (peek() != JsonToken.END_OBJECT) {
throw new IllegalStateException("Expected END_OBJECT but was " + peek() + locationString());
}
stackSize--;
if (stackSize == 0) {
closed = true;
}
pathIndices[stackSize - 1]++;
consumeValue();
}
}
3.4 处理嵌套对象和集合
当JSON数据包含嵌套对象或集合时,read方法需要递归处理这些嵌套结构。继续使用上面的User类示例,实现其完整的read方法:
class UserTypeAdapter extends TypeAdapter<User> {
private final TypeAdapter<Address> addressAdapter;
private final TypeAdapter<String> stringAdapter;
public UserTypeAdapter(Gson gson) {
addressAdapter = gson.getAdapter(Address.class);
stringAdapter = gson.getAdapter(String.class);
}
@Override
public User read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
User user = new User();
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
switch (name) {
case "name":
user.setName(in.nextString());
break;
case "address":
// 递归解析Address对象
user.setAddress(addressAdapter.read(in));
break;
case "hobbies":
// 解析hobbies集合
List<String> hobbies = new ArrayList<>();
in.beginArray();
while (in.hasNext()) {
hobbies.add(stringAdapter.read(in));
}
in.endArray();
user.setHobbies(hobbies);
break;
default:
in.skipValue();
break;
}
}
in.endObject();
return user;
}
// write方法省略
}
在这个例子中,我们通过Gson获取了Address和String的适配器,并在解析嵌套对象和集合时调用它们的read方法,实现了递归处理。
四、TypeAdapter的注册与发现机制
4.1 通过GsonBuilder注册TypeAdapter
在使用Gson时,需要通过GsonBuilder注册自定义的TypeAdapter。注册方法如下:
Gson gson = new GsonBuilder()
.registerTypeAdapter(User.class, new UserTypeAdapter())
.create();
GsonBuilder的registerTypeAdapter方法实现如下:
public final class GsonBuilder {
private final List<TypeAdapterFactory> factories = new ArrayList<>();
// 注册TypeAdapter的方法
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
if (type == null) {
throw new NullPointerException("type == null");
}
if (typeAdapter == null) {
throw new NullPointerException("typeAdapter == null");
}
// 将TypeAdapter包装为TypeAdapterFactory
factories.add(TypeAdapters.newFactory(TypeToken.get(type), typeAdapter));
return this;
}
// 创建Gson实例
public Gson create() {
List<TypeAdapterFactory> factories = new ArrayList<>();
// 添加用户注册的工厂
factories.addAll(this.factories);
// 添加Gson内置的工厂
factories.addAll(Gson.DEFAULT_FACTORIES);
return new Gson(factories);
}
}
4.2 TypeAdapter的发现过程
当Gson需要序列化或反序列化某个类型时,会通过TypeAdapterFactory查找对应的TypeAdapter。这个过程在Gson类的getAdapter方法中实现:
public final class Gson {
private final List<TypeAdapterFactory> factories;
// 获取TypeAdapter的方法
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
// 从缓存中查找TypeAdapter
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
// 为防止循环引用,先将一个占位符放入缓存
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// 检查是否存在循环引用
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
// 创建一个占位符
FutureTypeAdapter<T> call = new FutureTypeAdapter<>();
threadCalls.put(type, call);
// 遍历工厂列表,查找能够处理该类型的工厂
for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
// 找到适配器后,将其设置到占位符中
call.setDelegate(candidate);
// 将适配器存入缓存
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("Gson cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
}
4.3 TypeAdapterFactory的实现
TypeAdapterFactory是一个接口,用于创建TypeAdapter实例:
public interface TypeAdapterFactory {
// 为指定类型创建TypeAdapter
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
}
Gson提供了多种内置的TypeAdapterFactory,如:
- ReflectiveTypeAdapterFactory:基于反射处理普通Java对象
- CollectionTypeAdapterFactory:处理集合类型
- MapTypeAdapterFactory:处理Map类型
- ArrayTypeAdapter:处理数组类型
自定义TypeAdapterFactory的实现示例:
class CustomTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
// 判断是否为我们感兴趣的类型
if (type.getRawType() == User.class) {
// 返回自定义的TypeAdapter
return (TypeAdapter<T>) new UserTypeAdapter(gson);
}
// 不是我们感兴趣的类型,返回null
return null;
}
}
五、TypeAdapter的性能优化
5.1 避免中间Tree模型
TypeAdapter相比JsonSerializer和JsonDeserializer的一个重要优势是避免了中间Tree模型的使用。在使用JsonSerializer和JsonDeserializer时,Gson会先将JSON数据解析为JsonElement树结构,然后再进行处理,这会增加内存开销和处理时间。而TypeAdapter直接操作JsonWriter和JsonReader,避免了中间对象的创建,提高了性能。
5.2 缓存反射结果
在处理复杂对象时,反射操作可能成为性能瓶颈。可以通过缓存反射结果来优化性能。例如:
class UserTypeAdapter extends TypeAdapter<User> {
private final Constructor<User> constructor;
private final Field nameField;
private final Field ageField;
private final Field isAdminField;
public UserTypeAdapter() throws NoSuchMethodException, NoSuchFieldException {
// 获取构造函数并设置可访问
constructor = User.class.getDeclaredConstructor();
constructor.setAccessible(true);
// 获取字段并设置可访问
nameField = User.class.getDeclaredField("name");
nameField.setAccessible(true);
ageField = User.class.getDeclaredField("age");
ageField.setAccessible(true);
isAdminField = User.class.getDeclaredField("isAdmin");
isAdminField.setAccessible(true);
}
@Override
public User read(JsonReader in) throws IOException {
try {
// 使用缓存的构造函数创建实例
User user = constructor.newInstance();
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
switch (name) {
case "name":
// 使用缓存的字段设置值
nameField.set(user, in.nextString());
break;
case "age":
ageField.set(user, in.nextInt());
break;
case "isAdmin":
isAdminField.set(user, in.nextBoolean());
break;
default:
in.skipValue();
break;
}
}
in.endObject();
return user;
} catch (Exception e) {
throw new JsonSyntaxException(e);
}
}
// write方法省略
}
5.3 批量处理数据
在处理大量数据时,批量处理可以减少对象创建和方法调用的开销。例如,在处理集合时,可以批量读取或写入元素:
class UserListTypeAdapter extends TypeAdapter<List<User>> {
private final TypeAdapter<User> userAdapter;
public UserListTypeAdapter(Gson gson) {
userAdapter = gson.getAdapter(User.class);
}
@Override
public void write(JsonWriter out, List<User> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginArray();
// 批量处理元素
for (User user : value) {
userAdapter.write(out, user);
}
out.endArray();
}
@Override
public List<User> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
List<User> list = new ArrayList<>();
in.beginArray();
// 批量处理元素
while (in.hasNext()) {
list.add(userAdapter.read(in));
}
in.endArray();
return list;
}
}
六、TypeAdapter的高级应用
6.1 处理多态类型
当需要处理多态类型时,可以在TypeAdapter中根据对象的实际类型进行不同的处理。例如,假设我们有一个Shape接口和多个实现类:
interface Shape {
double getArea();
}
class Circle implements Shape {
private double radius;
// 构造方法和getter/setter省略
}
class Rectangle implements Shape {
private double width;
private double height;
// 构造方法和getter/setter省略
}
我们可以创建一个处理Shape接口的TypeAdapter:
class ShapeTypeAdapter extends TypeAdapter<Shape> {
private static final String TYPE_FIELD = "type";
private static final String CIRCLE = "circle";
private static final String RECTANGLE = "rectangle";
@Override
public void write(JsonWriter out, Shape value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginObject();
// 写入类型标识
if (value instanceof Circle) {
out.name(TYPE_FIELD).value(CIRCLE);
Circle circle = (Circle) value;
out.name("radius").value(circle.getRadius());
} else if (value instanceof Rectangle) {
out.name(TYPE_FIELD).value(RECTANGLE);
Rectangle rectangle = (Rectangle) value;
out.name("width").value(rectangle.getWidth());
out.name("height").value(rectangle.getHeight());
}
out.endObject();
}
@Override
public Shape read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
Shape shape = null;
in.beginObject();
String type = null;
double radius = 0;
double width = 0;
double height = 0;
while (in.hasNext()) {
String name = in.nextName();
switch (name) {
case TYPE_FIELD:
type = in.nextString();
break;
case "radius":
radius = in.nextDouble();
break;
case "width":
width = in.nextDouble();
break;
case "height":
height = in.nextDouble();
break;
default:
in.skipValue();
break;
}
}
in.endObject();
// 根据类型创建对象
if (CIRCLE.equals(type)) {
shape = new Circle(radius);
} else if (RECTANGLE.equals(type)) {
shape = new Rectangle(width, height);
}
return shape;
}
}
6.2 数据加密与解密
TypeAdapter还可以用于数据的加密和解密。例如,对敏感数据进行加密:
class EncryptedStringTypeAdapter extends TypeAdapter<String> {
private final Cipher encryptCipher;
private final Cipher decryptCipher;
public EncryptedStringTypeAdapter() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
// 初始化加密和解密的Cipher
SecretKeySpec secretKey = new SecretKeySpec("MySecretKey12345".getBytes(), "AES");
encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey);
decryptCipher = Cipher.getInstance("AES");
decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
}
@Override
public void write(JsonWriter out, String value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
try {
// 加密字符串
byte[] encryptedBytes = encryptCipher.doFinal(value.getBytes());
// 将加密后的字节数组转换为Base64编码
String encryptedString = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
out.value(encryptedString);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IOException("Encryption error", e);
}
}
@Override
public String read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String encryptedString = in.nextString();
try {
// 将Base64编码的字符串转换为字节数组
byte[] encryptedBytes = Base64.decode(encryptedString, Base64.DEFAULT);
// 解密字节数组
byte[] decryptedBytes = decryptCipher.doFinal(encryptedBytes);
return new String(decryptedBytes);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IOException("Decryption error", e);
}
}
}
6.3 自定义日期格式
TypeAdapter可以用于实现自定义的日期格式。例如:
class CustomDateTypeAdapter extends TypeAdapter<Date> {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
@Override
public void write(JsonWriter out, Date value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// 格式化日期
String formattedDate = dateFormat.format(value);
out.value(formattedDate);
}
@Override
public Date read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String dateString = in.nextString();
try {
// 解析日期
return dateFormat.parse(dateString);
} catch (ParseException e) {
throw new JsonSyntaxException("Invalid date format: " + dateString, e);
}
}
}
七、TypeAdapter与JsonReader/JsonWriter的协作
7.1 JsonReader的工作原理
JsonReader是Gson中用于读取JSON数据的核心类。它提供了一系列方法用于解析JSON的各种结构,如对象、数组、字符串、数字等。
JsonReader的核心机制是基于状态机的。它维护一个内部状态,指示当前正在解析的JSON结构的类型和位置。每次调用读取方法时,它会根据当前状态检查输入是否符合预期,并更新状态。
例如,当调用beginObject()方法时,JsonReader会检查当前字符是否为{,如果是,则进入对象解析状态;否则抛出异常。
7.2 JsonWriter的工作原理
JsonWriter是Gson中用于写入JSON数据的核心类。它提供了一系列方法用于生成JSON的各种结构,如对象、数组、字符串、数字等。
JsonWriter同样基于状态机工作。它维护一个内部状态,记录当前正在生成的JSON结构的类型和位置。每次调用写入方法时,它会根据当前状态生成适当的JSON语法,并更新状态。
例如,当调用beginObject()方法时,JsonWriter会写入{字符,并进入对象写入状态;当调用name()方法时,它会写入属性名,并更新状态为等待属性值。
7.3 TypeAdapter与JsonReader/JsonWriter的交互
TypeAdapter通过JsonReader和JsonWriter实现与JSON数据的交互。在反序列化时,TypeAdapter调用JsonReader的方法读取JSON数据;在序列化时,TypeAdapter调用JsonWriter的方法写入JSON数据。
这种交互模式使得TypeAdapter可以完全控制数据的转换过程,实现高度定制化的序列化和反序列化逻辑。
例如,在前面的UserTypeAdapter示例中,read方法调用JsonReader的beginObject()、nextName()、nextString()等方法读取JSON数据;write方法调用JsonWriter的beginObject()、name()、value()等方法写入JSON数据。
八、总结与展望
8.1 TypeAdapter的优势
TypeAdapter作为Gson的核心接口,具有以下优势:
- 高性能:直接操作JsonReader和JsonWriter,避免中间Tree模型,提高了序列化和反序列化的效率。
- 灵活性:可以完全控制数据的转换过程,实现高度定制化的序列化和反序列化逻辑。
- 类型安全:基于泛型的设计,提供了更好的类型安全性。
- 扩展性:可以通过TypeAdapterFactory动态提供适配器,支持复杂的类型处理。
8.2 TypeAdapter的未来发展
随着Android和Java技术的发展,TypeAdapter可能会在以下方向发展:
- Kotlin协程支持:更好地支持Kotlin协程,实现异步序列化和反序列化。
- 编译时处理:引入编译时注解处理,在编译期生成TypeAdapter代码,进一步提高性能。
- 多平台支持:在Kotlin Multiplatform项目中提供更好的支持,实现跨平台的数据转换。
- 简化API:提供更简洁的API,降低开发者使用门槛。
- 与其他框架集成:更紧密地集成其他Android和Java框架,如Room、Retrofit等。
通过不断优化和扩展,TypeAdapter将继续作为Gson的核心组件,为开发者提供高效、灵活的数据转换解决方案。