Подтвердить что ты не робот

GSON не вызывает мой TypeAdapter для типа, который является интерфейсом

GSON, похоже, делает какой-то трюк, где он смотрит на внутренние поля моих JavaBeans, вместо того, чтобы использовать общедоступную информацию о свойствах. К сожалению, это не полетит нам, потому что наш магически созданный beans полон частных полей, которые я не хочу хранить.

@Test
public void testJson() throws Exception
{
    Player player = new MagicPlayer(); //BeanUtils.createDefault(Player.class);
    player.setName("Alice");

    Gson gson = new GsonBuilder()
        .registerTypeAdapter(Player.class, new PlayerTypeAdapter())
        .create();

    System.out.println(gson.toJson(bean));
}

private static class PlayerTypeAdapter implements JsonSerializer<Player>
{
    @Override
    public JsonElement serialize(Player player, Type type,
                                 JsonSerializationContext context)
    {
        throw new RuntimeException("I got called, woohoo");
    }
}

public static interface Player //extends SupportsPropertyChanges
{
    public String getName();
    public void setName(String name);
}

// Simple implementation simulating what we're doing.
public static class MagicPlayer implements Player
{
    private final String privateStuff = "secret";
    private String name;

    @Override
    public String getName()
    {
        return name;
    }

    @Override
    public void setName(String name)
    {
        this.name = name;
    }
}

Это дает:

{"privateStuff":"secret","name":"Alice"}

И, конечно, никогда не называет мой адаптер типа, который, по-видимому, делает невозможным любое другое поведение.

4b9b3361

Ответ 1

У меня была та же проблема с текущей версией gson (2.3.1) и она работала с помощью

.registerTypeHierarchyAdapter(Player.class, new PlayerTypeAdapter())

вместо

.registerTypeAdapter(Player.class, new PlayerTypeAdapter())

Ответ 2

Текущая версия GSON не работает таким образом. Это приведет к сериализации вашего типа с помощью адаптера.

gson.toJson(bean, Player.class)

В качестве альтернативы вы можете зарегистрировать PlayerTypeAdapter для MagicPlayer.class, и ваш существующий код будет работать. GSON просматривает TypeAdapter только конкретным (или верхним уровнем). Таким образом, вам нужно будет зарегистрировать адаптер настраиваемого типа для каждого конкретного типа, с которым вы можете столкнуться.

Существует TypeHeirarchyAdapter, если вы хотите, чтобы тот же TypeAdapter использовался для всех расширяющих классов данного типа. Мне не повезло с этим, хотя я и не особо потратил время на то, чтобы понять, почему это не сработало для меня. Вот несколько соответствующих обсуждений: https://groups.google.com/forum/?fromgroups=#!searchin/google-gson/interface/google-gson/0ebOxifqwb0/OXSCNTiLpBQJ

Ответ 3

Почему это не работает:

  • PlayerTypeAdapter должен реализовывать JsonSerializer. Это?

  • Если это так, то нужно работать. Он работает идеально для меня, поэтому не вижу причин, почему он не работает для вас. Запустите приложение в отладке, поставьте контрольные точки и выписку. Должна быть какая-то причина.

В вашем тесте, где Gson Builder с адаптером? Вы должны изменить его:

public void testJson() throws Exception
{
    Player player = new MagicPlayer(); //BeanUtils.createDefault(Player.class);
    player.setName("Alice");

    // this is wrong if you want adapter
    /* Gson gson = new Gson(); */

    // this is what you nead
     Gson gson = new GsonBuilder()
        .registerTypeAdapter(Player.class, new PlayerTypeAdapter())
        .create();

    System.out.println(gson.toJson(bean));
}