繁体   English   中英

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

[英]How do I write a custom JSON deserializer for Gson?

我有一个 Java 类,用户:

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

我收到一个包含来自网络服务的用户对象的 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 反序列化器?

我将采用如下略有不同的方法,以最大程度地减少我的代码中的“手动”解析,因为不必要地这样做会在某种程度上违背我为什么首先使用像 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”。)

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

今天我正在寻找这个东西,因为我的班级有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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM