2013-06-09 50 views
12

Gson ist eine große Bibliothek - es funktioniert gut. Manchmal habe ich benutzerdefinierte Anforderungen und kann TypeAdapters und TypeAdaptorFactories erstellen und registrieren - und das funktioniert auch gut.Hinzufügen eines Objekts mit einem benutzerdefinierten Typadapter, Jsonwriter in Gson

Was mich jedoch verwirrt, ist, wie man wieder in json Serialisierung delegieren ... Meistens brauche ich das für Sammlungen, aber um den Punkt zu veranschaulichen - nehme an, ich hätte eine Paarklasse, die Gson würde offensichtlich glücklich serialisieren, aber aus irgendeinem Grund brauchte ich meinen eigenen benutzerdefinierten Serialisierer. Nun ja ... wenn mein Paar ist

public class Pair 
{ 
    public final Object First; 
    public final Object Second; 
    public Pair(Object first, Object second) {this.first = first; this.second = second}; 
} 

Wenn ich eine Art Adapter für diese geschrieben - Sie würden wollen die Schreibfunktion wie folgt aussehen:

public void write(JsonWriter out, Pair pair) 
{ 
    out.beginObject(); 
    out.name("first"); 
    out.value(pair.first);   // can't do this 
    out.name("second"); 
    out.value(pair.second);   // or this 
    out.endObject(); 
} 

So können Sie das Problem sehen - Ich habe keine Ahnung die Art der ersten und zweiten, noch wie sie serialisiert sind. Ich kann gson.toJson verwenden, um zuerst und die zweite zu serialisieren - aber wenn ich sie als Zeichenkette dem Schreiber hinzufüge, werden sie maskiert. Es gibt eine gson.tojson-Funktion, die einen Wert und einen Schreiber nimmt - aber es braucht auch einen Typenkopf - den ich nicht habe. Ich habe den Eindruck, dass ich irgendwo einen anderen Typ-Adapter haben soll - aber wenn ich nur eine Liste von Objekten habe ... Woher bekomme ich das? bekomme ich nur den Adapter für das Objekt?

Ich bin ein wenig verwirrt? Sicherlich ist dies der häufigste Anwendungsfall? Die meisten benutzerdefinierten Serializer werden für eine seltsame Liste von T oder Baum von T oder etwas sein, und Sie wissen wirklich nicht, was in der Liste ist, darüber hinaus erbt es von T ... so müssen Sie in der Lage sein, die zurück zu delegieren Serialisierung in irgendeiner Weise?

Wie auch immer - wenn jemand mir sagen kann, wie man die obige Funktion schreibt, würde ich es wirklich schätzen!

Antwort

22

In diesem Fall ist es besser, ein JsonSerializer zu verwenden, wie zu einem TypeAdapter Gegensatz, aus dem einfachen Grunde, dass Serializer Zugang zu ihrer Serialisierungskontext hat:

public class PairSerializer implements JsonSerializer<Pair> { 

    public PairSerializer() { 
     super(); 
    } 

    @Override 
    public JsonElement serialize(final Pair value, final Type type, 
      final JsonSerializationContext context) { 
     final JsonObject jsonObj = new JsonObject(); 
     jsonObj.add("first", context.serialize(value.getFirst())); 
     jsonObj.add("second", context.serialize(value.getSecond())); 

     return jsonObj; 
    } 
} 

Der obige Beispielcode zeigt, wie die Serialisierung von Ziel delegieren Objekte zurück zum Haupt-Marshaller. Der Hauptvorteil davon (abgesehen von der Vermeidung von komplizierten Problemumgehungen) besteht darin, dass Sie immer noch andere Typen von Adaptern und benutzerdefinierten Serialisierern nutzen können, die möglicherweise im Hauptkontext registriert wurden. Beachten Sie, dass die Registrierung von Serializer und Adapter verwenden, um den exakt gleichen Code:

// With adapter 
final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class, 
     new PairAdapter()).create(); 

// With serializer 
final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class, 
     new PairSerializer()).create(); 

Wenn Sie feststellen, dass Sie mit einem Adapter zu halten brauchen, dann können Sie eine eingebettete Gson Proxy verwenden, um die Pair-Eigenschaften für Sie serialisiert, mit der Nachteil, dass Sie den Zugriff auf benutzerdefinierte Registrierungen verlieren, die Sie auf dem übergeordneten Gson-Proxy vorgenommen haben:

+0

Vielen Dank - werden Sie das geben –

3

eigentlich schien das zu funktionieren - den Adapter für das Objekt zu bekommen - mit dem typadaptorfactory eine "json" -Methode für ein Objekt zu finden und das Adapterobjekt wegzubewahren. Scheint erstaunlich komplex für was ist so ein offensichtlicher Anwendungsfall?

zB:

public static @Nullable 
TypeAdapter<ImmutableStack<?>> json(final Gson gson) 
{ 
    final TypeAdapter<Object> adaptor = gson.getAdapter(Object.class); 
    return new TypeAdapter<ImmutableStack<?>>() 
    { 
     @Override 
     public ImmutableStack<?> read(@Nullable final JsonReader in) throws IOException 
     { 
      throw ProgramError.notImplementedYet(); 
     } 
     @Override 
     public void write(final JsonWriter out, final ImmutableStack<?> value) throws IOException 
     { 
      out.beginArray(); 
      for (final Object inner : value) 
       adaptor.write(out, inner); 
      out.endArray(); 
     } 
    }; 
} 

weiß jemand einen besseren Weg, es zu tun?

Verwandte Themen