简体   繁体   English

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

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

I have a Java class, User:我有一个 Java 类,用户:

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

And I receive a JSON list containing user objects from a webservice:我收到一个包含来自网络服务的用户对象的 JSON 列表:

[{"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?如何为 Gson 编写自定义 JSON 反序列化器?

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.我将采用如下略有不同的方法,以最大程度地减少我的代码中的“手动”解析,因为不必要地这样做会在某种程度上违背我为什么首先使用像 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 assumes that "date_date" should be "update_date", in the original question.) (这假设原始问题中的“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()));
}

I'm assuming User class has the appropriate constructor.我假设 User 类具有适当的构造函数。

Today I was looking for this thing as my class had java.time.Instant and the default gson could not deserialize it.今天我正在寻找这个东西,因为我的班级有java.time.Instant并且默认的 gson 无法反序列化它。 My POJOs look like this:我的 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
)

Then for Instant variables, I parse the json's time variables and convert string to Instant.然后对于Instant变量,我解析 json 的时间变量并将字符串转换为 Instant。 For integer , string, etc I use jsonObject.get("id").asInt etc. For other pojo, I use the default deserializer like this:对于 integer 、 string 等,我使用jsonObject.get("id").asInt等。对于其他 pojo,我使用默认的反序列化器,如下所示:

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:最后,我像这样创建我的自定义 gson:

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

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

相关问题 如何编写自定义的Jackson解串器,将包含原始json的json对象反序列化为单个对象? - How do I write a custom Jackson deserializer to deserialize a json object that contains raw json into a single object? 使用Gson的自定义JSON反序列化器 - Custom JSON deserializer using Gson 如何为嵌入式对象编写GSON自定义反序列化器,有两种可能的类型 - How to write GSON custom deserializer for embedded object with two possible types 如何为一个类的所有字段编写通用的自定义GSON解串器? - How to write common custom GSON deserializer for all fields of a class? 如何为 Jackson 编写自定义 JSON 解串器? - How to write custom JSON Deserializer for Jackson? 我可以将自定义解串器应用到 GSON 的另一个自定义解串器中吗 - Can I apply a custom deserializer to within another custom deserializer for GSON 如何调用Jackson中自定义反序列化器中的默认反序列化器? - How do I call the default deserializer in a custom deserializer in Jackson? 如何从 Jackson 中的自定义解串器调用默认解串器 - How do I call the default deserializer from a custom deserializer in Jackson Gson:如何为链接对象编写反序列化程序 - Gson: How to write Deserializer for Linked Objects 如何在自定义反序列化器Gson中小写JsonElement值? - How to lowercase the JsonElement value in the custom deserializer Gson?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM