【问题标题】:Force GSON to use specific constructor强制 GSON 使用特定的构造函数
【发布时间】:2011-05-31 12:41:52
【问题描述】:
public class UserAction {
    private final UUID uuid;
    private String userId;
    /* more fields, setters and getters here */

    public UserAction(){
        this.uuid = UUID.fromString(new com.eaio.uuid.UUID().toString());
    }

    public UserAction(UUID uuid){
        this.uuid = uuid;
    }
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final UserAction other = (UserAction) obj;
        if (this.uuid != other.uuid && (this.uuid == null || !this.uuid.equals(other.uuid))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 53 * hash + (this.uuid != null ? this.uuid.hashCode() : 0);
        return hash;
    }
}

我正在使用 Gson 来序列化和反序列化这个类。今天我不得不在这个对象中添加一个最终的 UUID。我序列化没有问题。我需要在反序列化时强制 gson 使用 public UserAction(UUID uuid) 构造函数。我怎样才能做到这一点?

【问题讨论】:

    标签: java constructor gson deserialization


    【解决方案1】:

    您可以实现自定义 JsonDeserializer 并将其注册到 GSON。

    class UserActionDeserializer implements JsonDeserializer<UserAction> {
        public UserAction deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException {
            return new UserAction(UUID.fromString(json.getAsString());
    }
    
    GsonBuilder gson = new GsonBuilder();
    gson.registerTypeAdapter(UserAction.class, new UserActionDeserializer());
    

    请记住,此代码尚未经过测试。

    【讨论】:

      【解决方案2】:

      解决此问题的另一种方法是利用这样一个事实,即在反序列化期间,Gson 将使用在 JSON 中找到的新值破坏构造函数设置的任何值,因此只需使用 InstanceCreator,它专门存在于“to创建未定义无参数构造函数的类的实例。”当要使用的构造函数仅将参数值分配给字段,并且不执行任何有效性检查或以其他方式执行任何有意义的基于状态的处理时,这种方法尤其适用。

      此外,这种方法不需要进一步的自定义反序列化——不需要JsonDeserializer 的自定义实现。这对于引入自定义反序列化器来解决一个小问题然后需要“手动”处理附近的其他 JSON 元素的情况非常有利,这可能很重要。

      话虽如此,这是一个使用首选UserAction 构造函数的有效解决方案,但只传递了一个空引用。 JSON 中的实际值稍后设置。 (Gson 不在乎 uuid 字段应该是最终的。)

      import java.lang.reflect.Type;
      import java.util.UUID;
      
      import com.google.gson.Gson;
      import com.google.gson.GsonBuilder;
      import com.google.gson.InstanceCreator;
      
      public class Foo
      {
        public static void main(String[] args)
        {
          UserAction action = new UserAction(UUID.randomUUID());
          action.setUserId("user1");
      
          String json = new Gson().toJson(action);
          System.out.println(json);
      
          GsonBuilder gsonBuilder = new GsonBuilder();
          gsonBuilder.registerTypeAdapter(UserAction.class, new UserActionInstanceCreator());
          Gson gson = gsonBuilder.create();
          UserAction actionCopy = gson.fromJson(json, UserAction.class);
          System.out.println(gson.toJson(actionCopy));
        }
      }
      
      class UserActionInstanceCreator implements InstanceCreator<UserAction>
      {
        @Override
        public UserAction createInstance(Type type)
        {
          return new UserAction(null);
        }
      }
      
      class UserAction
      {
        private final UUID uuid;
        private String userId;
      
        public UserAction()
        {
          throw new RuntimeException("this constructor is not used");
        }
      
        public UserAction(UUID uuid)
        {
          this.uuid = uuid;
        }
      
        void setUserId(String userId)
        {
          this.userId = userId;
        }
      }
      

      【讨论】:

      • 这非常优雅地为我解决了这个问题,并且没有添加大量样板。不错的一个
      【解决方案3】:
      gson.registerTypeAdapter(DateTime.class, new DateTimeDeserializer());
      
      private class DateTimeDeserializer implements JsonDeserializer<DateTime> {
        public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
          return new DateTime(json.getAsJsonPrimitive().getAsString());
        }
      }
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-26
      • 2017-03-19
      • 1970-01-01
      • 2012-06-29
      • 2014-09-26
      • 2011-12-17
      • 1970-01-01
      相关资源
      最近更新 更多