Другой подход к решению этой проблемы состоит в том, чтобы воспользоваться тем фактом, что во время десериализации Gson будет блокировать любые значения, заданные конструкторами, с новыми значениями, найденными в JSON, и поэтому просто использовать InstanceCreator , которыйсуществует специально для «создания экземпляров класса, который не определяет конструктор без аргументов».Этот подход особенно эффективен, когда используемый конструктор просто присваивает значения параметров полям и не выполняет никаких проверок достоверности или иным образом не выполняет какой-либо значимой обработки на основе состояния.
Кроме того, этот подход не требует дальнейшегопользовательская десериализация - пользовательская реализация JsonDeserializer
не требуется.Это может быть выгодно в ситуациях, когда введение пользовательского десериализатора для решения одной небольшой проблемы затем требует «ручной» обработки других элементов JSON в непосредственной близости, что может быть нетривиальным.
С учетом сказанного, вот такойрабочее решение, которое использует предпочтительный UserAction
конструктор, но передает ему только нулевую ссылку.Фактическое значение из JSON устанавливается позже.(Гсону все равно, что поле 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;
}
}