gpt4 book ai didi

java - 为 Google GSON 添加自定义 TypeAdapterFactory 以检测注释的使用以动态返回自定义 TypeAdapter

转载 作者:行者123 更新时间:2023-12-04 15:11:36 28 4
gpt4 key购买 nike

让我们从分享工作和可复制代码开始(需要谷歌gson包):

package mypackage;

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

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

public final class ALL {
static final Gson GSON = new GsonBuilder().registerTypeAdapterFactory(new Factory()).create();

/////////////////////////////////////////////////////////////////////

@Target( { METHOD, FIELD, ANNOTATION_TYPE, TYPE })
@Retention(RUNTIME)
public @interface Serialize {}

/////////////////////////////////////////////////////////////////////

public static void main(String[] args) {
Test test = new Test();

String json = GSON.toJson(test);

System.out.println(json);
}

/////////////////////////////////////////////////////////////////////

public static final class Test {
@Serialize
String abc = "def";
}

/////////////////////////////////////////////////////////////////////

public static final class Factory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Serialize annotation = type.getRawType().getAnnotation(Serialize.class);

boolean annotationPresent = type.getRawType().isAnnotationPresent(Serialize.class);

Annotation[] annotations = type.getRawType().getAnnotations();

if (annotationPresent) {
System.out.println("11111111111111");
}

if (annotation != null) {
return new Adapter<>();
}

return gson.getDelegateAdapter(this, type);
}
}

/////////////////////////////////////////////////////////////////////

public static final class Adapter<T> extends TypeAdapter<T> {
private static final java.util.Base64.Encoder ENCODER = java.util.Base64.getEncoder();
private static final java.util.Base64.Decoder DECODER = java.util.Base64.getDecoder();

@Override
public T read(JsonReader in) throws IOException {
in.beginObject();
String a = in.nextString();
in.endObject();

try {
return deserialize( DECODER.decode(a) );
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}

@Override
public void write(JsonWriter out, T value) throws IOException {
out.value( encode(serialize(value)) );
}

private String encode(byte[] serialize) {
return ENCODER.encodeToString( serialize );
}

private byte[] serialize(T value) throws IOException {
try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(out); ) {
os.writeObject(value);
return out.toByteArray();
}
}

private T deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream in = new ByteArrayInputStream(bytes); ObjectInputStream is = new ObjectInputStream(in); ) {
return (T) is.readObject();
}
}
}
}

如果我们查看 Test 类,目标是在存在注释 @Serialize 时输出其他内容。在这种情况下,我们以 String 形式输出字节。然后当我们读回它时,我们想反序列化它。

理解目标的其他方法是考虑使用注释来加密一个值,然后在回读时解密它。

这应该是可能的,不是吗?

我知道我可以根据字段类型注册 TypeAdapter,但是,我希望能够使用注释来声明意图。

没有包装器类。您可以创建自定义 JsonSerializer 但这需要注册。

在上面的示例中,type.getRawType().getAnnotation(Serialize.class); 始终返回 null 并且 Annotation[] annotations = type.getRawType().getAnnotations( ) 始终为空,因此无法使用工厂进行检测。

不确定如何动态检测注释。

你知道吗?

最佳答案

使用@JsonAdapter 怎么样?无论如何,您需要知道如何进行解密/加密,并且需要按类型实现。对于您的情况下的字符串,例如:

public class CryptoAdapter extends TypeAdapter<String> {
@Override
public void write(JsonWriter out, String value) throws IOException {
out.jsonValue(org.apache.commons.lang3.StringUtils.reverse(value));
}
@Override
public String read(JsonReader in) throws IOException {
return org.apache.commons.lang3.StringUtils.reverse(in.nextString());
}
}

用法:

public class Test {
@JsonAdapter(CryptoAdapter.class)
String abc = "def";
}

问题是 Gson 没有提供(据我所知)任何直接方法来创建一些自己的字段处理器,让用户读取字段/类成员注释。

换句话说,您需要在反序列化/序列化期间访问字段,而这似乎无法以简单的方式实现。

这就是为什么有这个 @JsonAdapter

如果有兴趣研究更多克隆source code from GitHub并检查:

public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory

不幸的是final。有一个名为 createBoundField 的方法(我认为这是为 fields 识别 @JsonAdapter 背后的逻辑)并且路径和覆盖该逻辑不是如此简单。

对于类(class),似乎有与您的解决方案非常相似的解决方案:

public final class JsonAdapterAnnotationTypeAdapterFactory
implements TypeAdapterFactory

当创建一个新的 Gson 时,上面提到的两者都会被添加到 TypeAdapterFactories 的列表中。

关于java - 为 Google GSON 添加自定义 TypeAdapterFactory 以检测注释的使用以动态返回自定义 TypeAdapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65130321/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com