2015-03-13 13 views
13

Ich habe Struktur JSON wie folgt -Nachrüst Gson Konverter für verschachtelte json mit verschiedenen Objekten

{ 
    "status": true, 
    "message": "Registration Complete.", 
    "data": { 
     "user": { 
      "username": "user88", 
      "email": "[email protected]", 
      "created_on": "1426171225", 
      "last_login": null, 
      "active": "1", 
      "first_name": "User", 
      "last_name": "", 
      "company": null, 
      "phone": null, 
      "sign_up_mode": "GOOGLE_PLUS" 
     } 
    } 
} 

Above Format üblich ist. Nur data Schlüssel verschiedene Arten von Informationen halten wie user, product, invoice usw.

Ich möchte status, message und data Tasten gleichen in jeder Rest Reaktion halten. data wird gemäß status behandelt und message wird dem Benutzer angezeigt.

Also grundsätzlich ist oben Format in allen Apis gewünscht. Nur Informationen innerhalb data Schlüssel wird jedes Mal anders sein.

Und ich habe Setup eine folgende Klasse und legen Sie es als Gson Konverter up - MyResponse.java

public class MyResponse<T> implements Serializable{ 
    private boolean status ; 
    private String message ; 
    private T data; 

    public boolean isStatus() { 
     return status; 
    } 

    public void setStatus(boolean status) { 
     this.status = status; 
    } 

    public String getMessage() { 
     return message; 
    } 

    public void setMessage(String message) { 
     this.message = message; 
    } 

    public T getData() { 
     return data; 
    } 

    public void setData(T data) { 
     this.data = data; 
    } 
} 

Deserializer.java

class Deserializer<T> implements JsonDeserializer<T>{ 
    @Override 
    public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException{ 
     JsonElement content = je.getAsJsonObject(); 

     // Deserialize it. You use a new instance of Gson to avoid infinite recursion to this deserializer 
     return new Gson().fromJson(content, type); 

    } 
} 

und benutzte es wie folgt -

GsonBuilder gsonBuilder = new GsonBuilder(); 
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); 
gsonBuilder.registerTypeAdapter(MyResponse.class, new Deserializer<MyResponse>()); 
...... ..... .... 

restBuilder.setConverter(new GsonConverter(gsonBuilder.create())); 

Service-Schnittstelle ist wie folgt -

@POST("/register") 
public void test1(@Body MeUser meUser, Callback<MyResponse<MeUser>> apiResponseCallback); 


@POST("/other") 
public void test2(Callback<MyResponse<Product>> apiResponseCallback); 

Problem

I status und message Felder von innen Rückruf zugreifen können. Aber Informationen innerhalb data Schlüssel wird nicht geparst und Modell wie MeUser und Product immer als leer zurückgegeben.

Wenn ich json Struktur folgende obigen Code ändern funktioniert perfekt -

{ 
     "status": true, 
     "message": "Registration Complete.", 
     "data": {     
       "username": "user88", 
       "email": "[email protected]", 
       "created_on": "1426171225", 
       "last_login": null, 
       "active": "1", 
       "first_name": "User", 
       "last_name": "", 
       "company": null, 
       "phone": null, 
       "sign_up_mode": "GOOGLE_PLUS" 
     } 
    } 

Wie kann ich es mit Angabe separater Schlüssel in data Objekt gearbeitet haben und es erfolgreich analysieren?

+0

möchte wissen, was Sie tun –

+0

GSON nicht berücksichtigen die generischen Datentypen 'private T-Daten;' während der Analyse. Es muss ein bestimmter Datentyp sein. –

+0

Verwenden Sie diese Datenklasse anstelle von 'T'.'Klasse Dataclass { \t \t @SerializedName ("user") \t \t Benutzerklasse Benutzer; // Benutzerobjekt \t \t @SerializedName ("Produkt") \t \t ProductClass Produkt; // Produkt Objekt \t \t @ SerializedName ("Rechnung") \t \t InvoiceClass Rechnung; // Rechnung Objekt \t \t Klasse Userclass { \t \t} \t \t Klasse ProductClass { \t \t} \t \t Klasse InvoiceClass { \t \t} \t} ' –

Antwort

22

Wenn ich vorschlagen kann, etwas in json zu ändern ist, dass man an einem neuen Feld hinzuzufügen, die die Art der Daten definiert, so unten aussehen json sollte:

{ 
    "status": true, 
    "message": "Registration Complete.", 
    "dataType" : "user", 
    "data": {     
      "username": "user88", 
      "email": "[email protected]", 
      "created_on": "1426171225", 
      "last_login": null, 
      "active": "1", 
      "first_name": "User", 
      "last_name": "", 
      "company": null, 
      "phone": null, 
      "sign_up_mode": "GOOGLE_PLUS" 
    } 
} 

Die MyResponse Klasse hat zu neuen DataType eingereicht haben, so sollte es wie folgt aussehen:

public class MyResponse<T> implements Serializable{ 
    private boolean status ; 
    private String message ; 
    private DataType dataType ; 
    private T data; 


    public DataType getDataType() { 
     return dataType; 
    } 

    //... other getters and setters 
} 

Die DataType ist eine Enumeration, welche Art von Daten definiert. Sie müssen Data.class als Parameter im Konstruktor übergeben. Für alle Datentypen müssen Sie neue Klassen erstellen. DataType Enum sollte wie folgt aussehen:

public enum DataType { 

    @SerializedName("user") 
    USER(MeUser.class), 
    @SerializedName("product") 
    Product(Product.class), 
    //other types in the same way, the important think is that 
    //the SerializedName value should be the same as dataType value from json 
    ; 


    Type type; 

    DataType(Type type) { 
     this.type = type; 
    } 

    public Type getType(){ 
     return type; 
    } 
} 

Die desarializator für Json sollte sieht aus wie folgt:

public class DeserializerJson implements JsonDeserializer<MyResponse> { 

    @Override 
    public MyResponse deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) 
      throws JsonParseException { 
     JsonObject content = je.getAsJsonObject(); 
     MyResponse message = new Gson().fromJson(je, type); 
     JsonElement data = content.get("data"); 
     message.setData(new Gson().fromJson(data, message.getDataType().getType())); 
     return message; 

    } 
} 

Und wenn Sie RestAdapter schaffen, in der Zeile, wo Sie Deserializator registrieren, sollten Sie diese verwenden:

Andere Klassen (Datentypen) definieren Sie wie Standard POJO für Gson in getrennten Klassen.

+0

Ist es möglich, die gesamte JSON-Antwort als ein Objekt von MyResponse.class mit 'success'- und' message'-Feld auch zurückzugeben? Im gonba muss es Nachricht entsprechend Status und Nachrichtenfeld anzeigen. Momentan gibt es nur den Datenschlüssel zurück. Musste nur den 'DeserializerJson' richtig einstellen ?? – Gimali

+0

Hoppla. Es tut was ich schon brauche. Groß. Ich werde prüfen, ob das auch zu anderen Jons passt. Sieht jetzt sauber und ordentlich aus. :) – Gimali

+0

Hast du meine Lösung versucht? Funktioniert es wie du willst? –

1

Ihr Problem ist, weil das data Attribut als T definiert, die Sie erwarten, dass die Typen MeUser, Product, etc, aber es ist tatsächlich ein Objekt, das wie user Innen Attribut hat. Um dies zu beheben, müssen Sie eine weitere Klassenstufe mit den erforderlichen Attributen user, product, invoice usw. einführen. Dies kann leicht mit statischen inneren Klassen erreicht werden.

public class MeUser{ 
    private User user; 
    public static class User{ 
    private String username; 
    //add other attributes of the User class 
    } 
} 
+0

Gibt es keine, durch die ich Wandler zu behandeln, erste Objekt in Daten zu behandeln als Typ und nicht Daten selbst? – Gimali

+0

Keine, die ich kenne. Vielleicht kann @JakeWharton erklären. – Rajesh

-1

Möglicherweise ein wenig off-topic, aber was passiert, wenn das innere Objekt eine Date-Eigenschaft enthält? Mein TypeAdapter sieht wie folgt aus:

.registerTypeAdapter(Date.class, new DateDeserializer()) 
       .registerTypeAdapter(GenericNotificationResponse.class, new NotificationDeserializer()) 
       .setDateFormat("yyyy-MM-dd'T'HH:mm:ss") 
       .create(); 

Aber aufgrund der Analyse, die durch das getan wird: message.setData(new Gson().fromJson(data, message.getDataType().getType()));

Es wirft einen Fehler, wenn sie versuchen, das Datum der Eigenschaft deserialisiert. Gibt es dafür eine schnelle Lösung?

EDIT: Markierte die Antwort als akzeptiert, definitiv :) es half mir mein Problem zu beheben. Aber jetzt gibt es dieses Problem mit dem Datum Deserializer.

Verwandte Themen