Принудительно использовать GSON для использования конкретного конструктора
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)
при десериализации. Как я могу это достичь?
Ответы
Ответ 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 будет clobber любые значения, установленные конструкторами с новыми значениями, найденными в 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;
}
}
Ответ 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());
}
}