Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON not calling my TypeAdapter for a type which is an interface

Tags:

java

json

gson

GSON appears to be doing some kind of trick where it looks at the internal fields of my JavaBeans instead of using the publically-accessible property information. Unfortunately this won't fly for us because our magically-created beans are full of private fields which I don't want it to store off.

@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;
    }
}

This gives:

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

And of course, never calls my type adapter, which seemingly makes it impossible to get any other behaviour.

like image 527
Hakanai Avatar asked May 17 '12 06:05

Hakanai


2 Answers

I had the same issue, with version 2.3.1 of Gson. I got it working by using

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

instead of

.registerTypeAdapter(Player.class, new PlayerTypeAdapter())
like image 159
nont Avatar answered Nov 18 '22 06:11

nont


Current release of GSON does not work this way. This will serialize your type using the adapter.

gson.toJson(bean, Player.class)

Alternatively you can register the PlayerTypeAdapter for MagicPlayer.class and your existing code will work. GSON looks up the TypeAdapter by the concrete (or top level) type only. So you will have to register a custom type adapter for every concrete type you may encounter.

There is TypeHeirarchyAdapter for when you want the same TypeAdapter to be used for all extending classes of a given type. I have not had good luck with this though and have not really spent time looking into why it has not worked well for me. Here is some relevant discussion: https://groups.google.com/forum/?fromgroups=#!searchin/google-gson/interface/google-gson/0ebOxifqwb0/OXSCNTiLpBQJ

like image 35
Eric Schoonover Avatar answered Nov 18 '22 06:11

Eric Schoonover