强制GSON使用特定的构造函数

时间:2011-05-31 12:41:52

标签: java constructor gson deserialization

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对这个类进行serilize和反序列化。就像今天一样,我必须在这个对象中添加一个最终的UUID。我没有问题序列化。我需要在反序列化时强制gson使用public UserAction(UUID uuid)构造函数。我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:22)

您可以实现自定义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());

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

答案 1 :(得分:12)

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

此外,此方法不需要进一步自定义反序列化 - 不需要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;
  }
}

答案 2 :(得分:0)

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());
  }
}