java—为google gson添加自定义typeadapterfactory,以检测注解的使用情况,从而动态返回自定义typeadapter

7bsow1i6  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(611)

让我们从共享工作和可复制的代码开始(需要google gson包):

  1. package mypackage;
  2. import com.google.gson.Gson;
  3. import com.google.gson.GsonBuilder;
  4. import com.google.gson.TypeAdapter;
  5. import com.google.gson.TypeAdapterFactory;
  6. import com.google.gson.reflect.TypeToken;
  7. import com.google.gson.stream.JsonReader;
  8. import com.google.gson.stream.JsonWriter;
  9. import java.io.*;
  10. import java.lang.annotation.Annotation;
  11. import java.lang.annotation.Retention;
  12. import java.lang.annotation.Target;
  13. import static java.lang.annotation.ElementType.*;
  14. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  15. public final class ALL {
  16. static final Gson GSON = new GsonBuilder().registerTypeAdapterFactory(new Factory()).create();
  17. /////////////////////////////////////////////////////////////////////
  18. @Target( { METHOD, FIELD, ANNOTATION_TYPE, TYPE })
  19. @Retention(RUNTIME)
  20. public @interface Serialize {}
  21. /////////////////////////////////////////////////////////////////////
  22. public static void main(String[] args) {
  23. Test test = new Test();
  24. String json = GSON.toJson(test);
  25. System.out.println(json);
  26. }
  27. /////////////////////////////////////////////////////////////////////
  28. public static final class Test {
  29. @Serialize
  30. String abc = "def";
  31. }
  32. /////////////////////////////////////////////////////////////////////
  33. public static final class Factory implements TypeAdapterFactory {
  34. @Override
  35. public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
  36. Serialize annotation = type.getRawType().getAnnotation(Serialize.class);
  37. boolean annotationPresent = type.getRawType().isAnnotationPresent(Serialize.class);
  38. Annotation[] annotations = type.getRawType().getAnnotations();
  39. if (annotationPresent) {
  40. System.out.println("11111111111111");
  41. }
  42. if (annotation != null) {
  43. return new Adapter<>();
  44. }
  45. return gson.getDelegateAdapter(this, type);
  46. }
  47. }
  48. /////////////////////////////////////////////////////////////////////
  49. public static final class Adapter<T> extends TypeAdapter<T> {
  50. private static final java.util.Base64.Encoder ENCODER = java.util.Base64.getEncoder();
  51. private static final java.util.Base64.Decoder DECODER = java.util.Base64.getDecoder();
  52. @Override
  53. public T read(JsonReader in) throws IOException {
  54. in.beginObject();
  55. String a = in.nextString();
  56. in.endObject();
  57. try {
  58. return deserialize( DECODER.decode(a) );
  59. } catch (ClassNotFoundException e) {
  60. throw new RuntimeException(e);
  61. }
  62. }
  63. @Override
  64. public void write(JsonWriter out, T value) throws IOException {
  65. out.value( encode(serialize(value)) );
  66. }
  67. private String encode(byte[] serialize) {
  68. return ENCODER.encodeToString( serialize );
  69. }
  70. private byte[] serialize(T value) throws IOException {
  71. try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(out); ) {
  72. os.writeObject(value);
  73. return out.toByteArray();
  74. }
  75. }
  76. private T deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
  77. try (ByteArrayInputStream in = new ByteArrayInputStream(bytes); ObjectInputStream is = new ObjectInputStream(in); ) {
  78. return (T) is.readObject();
  79. }
  80. }
  81. }
  82. }

如果我们看看 Test 类,目标是在注解 @Serialize 存在。在本例中,我们以字符串形式输出字节。当我们读回这个时,我们想反序列化它。
理解这个目标的另一种方法是考虑使用一个注解来加密一个值,然后在readback上解密它。
这应该是可能的,不是吗?
我知道我可以基于字段类型注册typeadapters,但是,我希望能够使用注解来声明意图。
没有 Package 类。您可以创建自定义jsonserializer,但这需要注册。
在上面的例子中 type.getRawType().getAnnotation(Serialize.class); 总是返回null和 Annotation[] annotations = type.getRawType().getAnnotations() 总是空的,所以无法检测使用工厂。
不确定如何动态检测注解。
你知道吗?

avkwfej4

avkwfej41#

使用@jsonadapter怎么样?无论如何,您需要知道如何进行解密,并且需要实现每个类型的tha。例如,对于本例中的字符串:

  1. public class CryptoAdapter extends TypeAdapter<String> {
  2. @Override
  3. public void write(JsonWriter out, String value) throws IOException {
  4. out.jsonValue(org.apache.commons.lang3.StringUtils.reverse(value));
  5. }
  6. @Override
  7. public String read(JsonReader in) throws IOException {
  8. return org.apache.commons.lang3.StringUtils.reverse(in.nextString());
  9. }
  10. }

用法:

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

问题是,据我所知,gson没有提供任何直接的方法来创建一些自己的字段处理器,使用户可以读取字段/类成员注解。
换句话说,您需要在反序列化/序列化期间访问该字段,这似乎不可能以简单的方式实现。
所以才有这个 @JsonAdapter .
如果有兴趣从github学习更多克隆源代码,请检查:

  1. public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory

不幸的是 final . 有一个名为 createBoundField (我认为这就是 @JsonAdapter 对于字段),路径和重写该逻辑并不是那么简单。
对于类,似乎有与您的解决方案非常相似的解决方案:

  1. public final class JsonAdapterAnnotationTypeAdapterFactory
  2. implements TypeAdapterFactory

上述两项均已列入 TypeAdapterFactories 当一个新的 Gson 已创建。

展开查看全部

相关问题