Десериализация интерфейса в GSON - PullRequest
6 голосов
/ 22 октября 2011

Не могу придумать лучшего выражения для этого вопроса, но в основном я хочу сохранить имя конкретного класса в GSON (см. «Движение»):

{ 
    "player" : {
        "position" : { "x" : 300, "y" : 400 },
        "scale" : 1,
        "rotation" : 0,
        "sprite" : {
            "frames" : [ { 
                "fileName" : "data/plane.png"
            } ],
            "duration" : 1
        }
    },
    "movementDelay" : { "elapsed" : 0, "started" : 0, "delay" : 150 },
    "movement" : { "class" : "controller.TopDownGridMovement" }
}

Это класс, который содержитинтерфейс Movement, который я хочу десериализовать:

public class PlayerController {
    private Player player;
    private DelayTimer movementDelay;
    private Movement movement;

    public PlayerController() {
    }

    [...]
}

Я написал пользовательский десериализатор:

package gson;

import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import controller.Movement;

public class MovementDeserialiser implements JsonDeserializer<Movement> {

    @Override
    public Movement deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        try {
            JsonObject obj = (JsonObject) json;
            Class clazz = Class.forName(obj.get("class").getAsString());
            return (Movement) clazz.newInstance();
        } catch (Exception e) {
            throw new JsonParseException(e.getMessage());
        }
    }

}

Я зарегистрировал десериализатор:

public void registerAdapters(GsonBuilder gsonBuilder) {
    gsonBuilder.registerTypeAdapter(Image.class, new ImageDeserialiser());
    gsonBuilder.registerTypeAdapter(Button.class, new ButtonDeserialiser());
    gsonBuilder.registerTypeAdapter(Animation.class, new AnimationDeserialiser());
    gsonBuilder.registerTypeAdapter(Movement.class, new MovementDeserialiser());
}

Затем я попыталсядесериализовать класс, который содержит интерфейс Movement:

playerController = gson.fromJson(new FileReader("data/player_data/player_data.json"), PlayerController.class);

Но я получаю эту ошибку:

ОШИБКА: невозможно вызвать конструктор без аргументов для контроллера controller.Movement.Регистрация InstanceCreator в Gson для этого типа может решить эту проблему.

Что мне нужно сделать, чтобы это работало?Идея указать класс для загрузки возникла из настроек Spring bean - не уверен, есть ли лучший способ сделать это.

О, и из прочитанного, который я сделал, я решил, что не должендолжен создать InstanceCreator для движения.Я предоставляю собственный десериализатор, в конце концов ...

Приветствия.

Ответы [ 2 ]

0 голосов
/ 22 октября 2011

Ах ... Я ранее создавал новый экземпляр Gson везде, где мне это было нужно, но недавно создал синглтон GsonInstance, в котором я регистрировал свои собственные сериализаторы.Объект Gson, из которого десериализован объект Movement, не был объектом GsonInstance, поэтому, по-моему, он не знал, как его сериализовать.Глупая ошибка.

tl; dr: Я не зарегистрировал пользовательский сериализатор с конкретным экземпляром Gson, который использовал.

0 голосов
/ 22 октября 2011

Убедитесь, что controller.TopDownGridMovement имеет конструктор без аргументов.Если это не так, вы не можете создать экземпляр класса, используя:

return (Movement) clazz.newInstance();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...