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

bqucvtff  于 2022-11-23  发布在  其他
关注(0)|答案(3)|浏览(187)

我有一个Java类User:

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

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

[{"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反序列化器呢?

km0tfn4u

km0tfn4u1#

我将采取如下稍微不同的方法,以便最大限度地减少代码中的“手动”解析,因为不必要地这样做会在某种程度上违背我最初使用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);
  }
}

(This假设“date_date”应为原始问题中的“update_date”。)

ktecyv1j

ktecyv1j2#

@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类具有适当的构造函数。

ctrmrzij

ctrmrzij3#

今天我在寻找这个东西,因为我的类有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。对于integer、string等,我使用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();

相关问题