如何为 Gson 编写自定义 JSON 反序列化器?

发布于 2024-11-08 23:34:53 字数 791 浏览 0 评论 0原文

我有一个 Java 类 User:

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

我收到一个包含来自 Web 服务的用户对象的 JSON 列表:

[{"id":1,"name":"Jonas","update_date":"1300962900226"},
{"id":5,"name":"Test","date_date":"1304782298024"}]

我尝试编写一个自定义反序列化器:

@Override
public User deserialize(JsonElement json, Type type,
                        JsonDeserializationContext context) throws JsonParseException {

        return new User(
            json.getAsJsonPrimitive().getAsInt(),
            json.getAsString(),
            json.getAsInt(),
            (Timestamp)context.deserialize(json.getAsJsonPrimitive(),
            Timestamp.class));
}

但我的反序列化器不起作用。如何为 Gson 编写自定义 JSON 反序列化器?

I have a Java class, User:

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

And I receive a JSON list containing user objects from a webservice:

[{"id":1,"name":"Jonas","update_date":"1300962900226"},
{"id":5,"name":"Test","date_date":"1304782298024"}]

I have tried to write a custom deserializer:

@Override
public User deserialize(JsonElement json, Type type,
                        JsonDeserializationContext context) throws JsonParseException {

        return new User(
            json.getAsJsonPrimitive().getAsInt(),
            json.getAsString(),
            json.getAsInt(),
            (Timestamp)context.deserialize(json.getAsJsonPrimitive(),
            Timestamp.class));
}

But my deserializer doesn't work. How can I write a custom JSON deserializer for Gson?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

行雁书 2024-11-15 23:34:53

我会采取如下稍微不同的方法,以便最大限度地减少代码中的“手动”解析,因为不必要地这样做会在某种程度上违背我首先使用像 Gson 这样的 API 的目的。

// output:
// [User: id=1, name=Jonas, updateDate=2011-03-24 03:35:00.226]
// [User: id=5, name=Test, updateDate=2011-05-07 08:31:38.024]

// using java.sql.Timestamp

public class Foo
{
  static String jsonInput = 
    "[" +
      "{\"id\":1,\"name\":\"Jonas\",\"update_date\":\"1300962900226\"}," +
      "{\"id\":5,\"name\":\"Test\",\"update_date\":\"1304782298024\"}" +
    "]";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampDeserializer());
    Gson gson = gsonBuilder.create();
    User[] users = gson.fromJson(jsonInput, User[].class);
    for (User user : users)
    {
      System.out.println(user);
    }
  }
}

class User
{
  int id;
  String name;
  Timestamp updateDate;

  @Override
  public String toString()
  {
    return String.format(
      "[User: id=%1$d, name=%2$s, updateDate=%3$s]",
      id, name, updateDate);
  }
}

class TimestampDeserializer implements JsonDeserializer<Timestamp>
{
  @Override
  public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    long time = Long.parseLong(json.getAsString());
    return new Timestamp(time);
  }
}

(这假设原始问题中的“date_date”应该是“update_date”。)

I'd take a slightly different approach as follows, so as to minimize "manual" parsing in my code, as unnecessarily doing otherwise somewhat defeats the purpose of why I'd use an API like Gson in the first place.

// output:
// [User: id=1, name=Jonas, updateDate=2011-03-24 03:35:00.226]
// [User: id=5, name=Test, updateDate=2011-05-07 08:31:38.024]

// using java.sql.Timestamp

public class Foo
{
  static String jsonInput = 
    "[" +
      "{\"id\":1,\"name\":\"Jonas\",\"update_date\":\"1300962900226\"}," +
      "{\"id\":5,\"name\":\"Test\",\"update_date\":\"1304782298024\"}" +
    "]";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampDeserializer());
    Gson gson = gsonBuilder.create();
    User[] users = gson.fromJson(jsonInput, User[].class);
    for (User user : users)
    {
      System.out.println(user);
    }
  }
}

class User
{
  int id;
  String name;
  Timestamp updateDate;

  @Override
  public String toString()
  {
    return String.format(
      "[User: id=%1$d, name=%2$s, updateDate=%3$s]",
      id, name, updateDate);
  }
}

class TimestampDeserializer implements JsonDeserializer<Timestamp>
{
  @Override
  public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    long time = Long.parseLong(json.getAsString());
    return new Timestamp(time);
  }
}

(This assumes that "date_date" should be "update_date", in the original question.)

初见 2024-11-15 23:34:53
@Override
public User deserialize(JsonElement json, Type type,
        JsonDeserializationContext context) throws JsonParseException {

    JsonObject jobject = json.getAsJsonObject();

    return new User(
            jobject.get("id").getAsInt(), 
            jobject.get("name").getAsString(), 
            new Timestamp(jobject.get("update_date").getAsLong()));
}

我假设 User 类有适当的构造函数。

@Override
public User deserialize(JsonElement json, Type type,
        JsonDeserializationContext context) throws JsonParseException {

    JsonObject jobject = json.getAsJsonObject();

    return new User(
            jobject.get("id").getAsInt(), 
            jobject.get("name").getAsString(), 
            new Timestamp(jobject.get("update_date").getAsLong()));
}

I'm assuming User class has the appropriate constructor.

囍笑 2024-11-15 23:34:53

今天我正在寻找这个东西,因为我的类有 java.time.Instant 并且默认的 gson 无法反序列化它。我的 POJO 如下所示:

open class RewardResult(
  @SerializedName("id")
  var id: Int,
  @SerializedName("title")
  var title: String?,
  @SerializedName("details")
  var details: String?,
  @SerializedName("image")
  var image: String?,
  @SerializedName("start_time")
  var startTimeUtcZulu: Instant?,   // Unit: Utc / Zulu. Unit is very important
  @SerializedName("end_time")
  var endTimeUtcZulu: Instant?,
  @SerializedName("unlock_expiry")
  var unlockExpiryTimeUtcZulu: Instant?,
  @SerializedName("target")
  var target: Int,
  @SerializedName("reward")
  var rewardItem: RewardItem
);

data class RewardItem(
  @SerializedName("type")
  var type: String?,
  @SerializedName("item_id")
  var itemId: Int,
  @SerializedName("amount")
  var amount: Int
)

然后,对于 Instant 变量,我解析 json 的时间变量并将字符串转换为 Instant。对于整数、字符串等,我使用 jsonObject.get("id").asInt 等。对于其他 pojo,我使用默认的反序列化器,如下所示:

val rewardItem: RewardItem = context!!.deserialize(rewardJsonElement,
        RewardItem::class.java);

因此相应的自定义反序列化器如下所示:

  val customDeserializer: JsonDeserializer<RewardResult> = object : JsonDeserializer<RewardResult> {
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): RewardResult {
      val jsonObject: JsonObject = json!!.asJsonObject;

      val startTimeString: String? = jsonObject.get("start_time")?.asString;
      var startTimeUtcZulu: Instant? = createTimeInstant(startTimeString);


      val endTimeString: String? = jsonObject.get("end_time")?.asString;
      var endTimeUtcZulu: Instant? = createTimeInstant(endTimeString);

      val unlockExpiryStr: String? = jsonObject.get("unlock_expiry")?.asString;
      var unlockExpiryUtcZulu: Instant? = createTimeInstant(unlockExpiryStr);

      val rewardJsonElement: JsonElement = jsonObject.get("reward");
      val rewardItem: ridmik.one.modal.reward.RewardItem = context!!.deserialize(rewardJsonElement,
          ridmik.one.modal.reward.RewardItem::class.java);  // I suppose this line means use the default jsonDeserializer

      var output: ridmik.one.modal.reward.RewardResult = ridmik.one.modal.reward.RewardResult(
          id = jsonObject.get("id").asInt,
          title = jsonObject.get("title")?.asString,
          details = jsonObject.get("details")?.asString,
          image = jsonObject.get("image")?.asString,
          startTimeUtcZulu = startTimeUtcZulu,
          endTimeUtcZulu = endTimeUtcZulu,
          unlockExpiryTimeUtcZulu = unlockExpiryUtcZulu,
          target = jsonObject.get("target").asInt,
          rewardItem = rewardItem
      );

      Timber.tag(TAG).e("output = "+output);

      return output;
    }

  }

最后,我像这样创建自定义 gson:

 val gsonBuilder = GsonBuilder();
 gsonBuilder.registerTypeAdapter(RewardResult::class.javaObjectType,
          this.customJsonDeserializer);
      val customGson: Gson = gsonBuilder.create();

Today I was looking for this thing as my class had java.time.Instant and the default gson could not deserialize it. My POJOs look like this:

open class RewardResult(
  @SerializedName("id")
  var id: Int,
  @SerializedName("title")
  var title: String?,
  @SerializedName("details")
  var details: String?,
  @SerializedName("image")
  var image: String?,
  @SerializedName("start_time")
  var startTimeUtcZulu: Instant?,   // Unit: Utc / Zulu. Unit is very important
  @SerializedName("end_time")
  var endTimeUtcZulu: Instant?,
  @SerializedName("unlock_expiry")
  var unlockExpiryTimeUtcZulu: Instant?,
  @SerializedName("target")
  var target: Int,
  @SerializedName("reward")
  var rewardItem: RewardItem
);

data class RewardItem(
  @SerializedName("type")
  var type: String?,
  @SerializedName("item_id")
  var itemId: Int,
  @SerializedName("amount")
  var amount: Int
)

Then for Instant variables, I parse the json's time variables and convert string to Instant. For integer , string, etc I use jsonObject.get("id").asInt etc. For other pojo, I use the default deserializer like this:

val rewardItem: RewardItem = context!!.deserialize(rewardJsonElement,
        RewardItem::class.java);

So the corresponding custom deserializer looks like this:

  val customDeserializer: JsonDeserializer<RewardResult> = object : JsonDeserializer<RewardResult> {
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): RewardResult {
      val jsonObject: JsonObject = json!!.asJsonObject;

      val startTimeString: String? = jsonObject.get("start_time")?.asString;
      var startTimeUtcZulu: Instant? = createTimeInstant(startTimeString);


      val endTimeString: String? = jsonObject.get("end_time")?.asString;
      var endTimeUtcZulu: Instant? = createTimeInstant(endTimeString);

      val unlockExpiryStr: String? = jsonObject.get("unlock_expiry")?.asString;
      var unlockExpiryUtcZulu: Instant? = createTimeInstant(unlockExpiryStr);

      val rewardJsonElement: JsonElement = jsonObject.get("reward");
      val rewardItem: ridmik.one.modal.reward.RewardItem = context!!.deserialize(rewardJsonElement,
          ridmik.one.modal.reward.RewardItem::class.java);  // I suppose this line means use the default jsonDeserializer

      var output: ridmik.one.modal.reward.RewardResult = ridmik.one.modal.reward.RewardResult(
          id = jsonObject.get("id").asInt,
          title = jsonObject.get("title")?.asString,
          details = jsonObject.get("details")?.asString,
          image = jsonObject.get("image")?.asString,
          startTimeUtcZulu = startTimeUtcZulu,
          endTimeUtcZulu = endTimeUtcZulu,
          unlockExpiryTimeUtcZulu = unlockExpiryUtcZulu,
          target = jsonObject.get("target").asInt,
          rewardItem = rewardItem
      );

      Timber.tag(TAG).e("output = "+output);

      return output;
    }

  }

Finally, I create my custom gson like this:

 val gsonBuilder = GsonBuilder();
 gsonBuilder.registerTypeAdapter(RewardResult::class.javaObjectType,
          this.customJsonDeserializer);
      val customGson: Gson = gsonBuilder.create();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文