2012-05-17 2 views
19

GSON sembra che stia facendo una specie di trucco dove guarda i campi interni dei miei JavaBeans invece di usare le informazioni di proprietà accessibili pubblicamente. Sfortunatamente questo non volerà per noi perché i nostri fagioli magicamente creati sono pieni di campi privati ​​che non voglio che vengano archiviati.GSON non chiama il mio TypeAdapter per un tipo che è un'interfaccia

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

Questo dà:

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

E, naturalmente, non chiama mai il mio adattatore tipo, che rende apparentemente impossibile ottenere qualsiasi altro comportamento.

+0

Could aggiungi il codice che chiama Gson.toJson()? –

+0

Non è chiaro che questo sia lo stesso problema, ma mi sono imbattuto in qualcosa di simile qualche tempo fa, forse ti aiuterà: http://stackoverflow.com/questions/5952595/serializing-list-of-interfaces-gson/15557654# 15557654 – dimo414

risposta

-1

Perché non funziona:

  1. PlayerTypeAdapter dovrebbe implementa JsonSerializer. Lo fa?

  2. Se lo fa, dovrebbe funzionare. Funziona perfettamente per me, quindi non vedo il motivo per cui non funziona per te. Avvia l'applicazione in debug, inserisci breakpoint e checkout. Ci dovrebbe essere una ragione.

Nel test in cui si trova Gson builder con adattatore? È necessario modificarlo:

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)); 
} 
+0

Puoi vedere nella domanda sopra come è implementato PlayerTypeAdapter. Metto un punto di interruzione sulla linea in cui lancio l'eccezione, ma la linea non viene mai raggiunta. Ergo, Gson non sta chiamando il mio serializzatore. Ci deve essere qualcos'altro che dovrei fare. Oppure, oppure Gson non chiama gli adattatori di tipo per le interfacce (il che significa che non posso usarlo). – Trejkaz

+0

Ok, aggiornato per rimuovere CGLIB dall'equazione. Gson continua a non chiamare il mio tipo di adattatore in nessun punto. – Trejkaz

+2

Leggere la domanda prima di aggiornare ulteriormente la risposta. – Trejkaz

9

L'attuale versione di GSON non funziona in questo modo. Questo serializzerà il tuo tipo usando l'adattatore.

gson.toJson(bean, Player.class)

In alternativa è possibile registrare il PlayerTypeAdapter per MagicPlayer.class e il tuo codice esistente funzionerà. GSON cerca il TypeAdapter solo dal tipo concreto (o di primo livello). Quindi dovrai registrare un adattatore di tipo personalizzato per ogni tipo di calcestruzzo che potresti incontrare.

C'è TypeHeirarchyAdapter per quando si desidera utilizzare lo stesso TypeAdapter per tutte le classi di estensione di un determinato tipo. Non ho avuto fortuna con questo e non ho passato molto tempo a capire perché non ha funzionato bene per me. Ecco alcune discussioni rilevanti: https://groups.google.com/forum/?fromgroups=#!searchin/google-gson/interface/google-gson/0ebOxifqwb0/OXSCNTiLpBQJ

+0

Questo risponde alla parte principale della domanda sul perché non funziona.Non risolve esattamente il problema o rende GSON utilizzabile in qualsiasi modo, perché fare affidamento sul codice per dire che il tipo di tutto non funzionerà mai. ad esempio, esiste un altro luogo in cui ho un elenco in cui ogni oggetto può essere di qualsiasi tipo. Ora cosa dovrei fare? – Trejkaz

+0

La seconda parte della domanda spiega cosa fare. Per ogni tipo di calcestruzzo è necessario registrare il 'TypeAdapter' che si desidera utilizzare. –

37

Ho avuto lo stesso problema, con la versione corrente di GSON (2.3.1) e ottenuto che funziona utilizzando

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

invece di

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

Questo dovrebbe essere accettato come risposta. Funziona con java.util.Calendar (il tipo effettivo è java.util.GregorianCalendar) –