使用 GSon 从 JSon 转换为多个未知的 Java 对象类型

2022-09-03 01:42:16

我有一个netty解码器,它使用GSon将来自Web客户端的JSon转换为适当的java对象。要求是:客户端可以发送不相关的类,类A,类B,类C等,但我想在管道中使用相同的单例解码器实例进行转换(因为我使用spring进行配置)。我面临的问题是我需要事先知道物体。class

public Object decode()
{
    gson.fromJson(jsonString, A.class);
}

这无法解码 B 或 C。我的库的用户现在需要为每个类编写单独的解码器,而不是稍后进行转换。我能看到的唯一方法是从Web客户端传递类的字符串名称“org.example.C”在JSon字符串中,在解码器中解析它,然后用于获取类。有没有更好的方法来做到这一点?Class.forName


答案 1

GSon 必须知道与 json 字符串匹配的类。如果你不想用 fromJson() 来提供它,你实际上可以在 Json 中指定它。一种方法是定义一个接口并在其上绑定适配器。

喜欢:

  class A implements MyInterface {
    // ...
  }

  public Object decode()
  {
    Gson  gson = builder.registerTypeAdapter(MyInterface.class, new MyInterfaceAdapter());
    MyInterface a =  gson.fromJson(jsonString, MyInterface.class);
  }

适配器可以是这样的:

public final class MYInterfaceAdapter implements JsonDeserializer<MyInterface>, JsonSerializer<MyInterface> {
  private static final String PROP_NAME = "myClass";

  @Override
  public MyInterface deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    try {
      String classPath = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
      Class<MyInterface> cls = (Class<MyInterface>) Class.forName(classPath);

      return (MyInterface) context.deserialize(json, cls);
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    return null;
  }

  @Override
  public JsonElement serialize(MyInterface src, Type typeOfSrc, JsonSerializationContext context) {
    // note : won't work, you must delegate this
    JsonObject jo = context.serialize(src).getAsJsonObject();

    String classPath = src.getClass().getName();
    jo.add(PROP_NAME, new JsonPrimitive(classPath));

    return jo;
  }
}

答案 2

假设您有以下 2 个可能的 JSON 响应:

{
  "classA": {"foo": "fooValue"}
}
  or
{
  "classB": {"bar": "barValue"}
}

您可以创建如下类结构:

public class Response {
  private A classA;
  private B classB;
  //more possible responses...
  //getters and setters...
}

public class A {
  private String foo;
  //getters and setters...
}

public class B {
  private String bar;
  //getters and setters...
}

然后,您可以使用以下命令解析任何可能的 JSON 响应:

Response response = gson.fromJson(jsonString, Response.class);

Gson 将忽略所有与类结构中的任何属性都不对应的 JSON 字段,因此您可以调整单个类来解析不同的响应...

然后,您可以检查哪些属性 , , ...不是,您将知道您收到了哪个响应。classAclassBnull