Benutzerdefinierter Konverter zur Unterklasse mit Moshi

Ich habe eine User-Klasse. Und zwei Unterklassen. Eltern und Kind. Ich bekomme json von meinem Server mit {"user": "…"} und musst es in das übergeordnete oder auf das Kind umwandeln, je nach user.type

Wie ich verstehe, muss ich benutzerdefinierten Konverter auf diese Weise hinzufügen:

  • Streaming Video (oder Progressive Download) zum Droid Browser
  • Wie mache ich ein .jar aus einem Android Studio Projekt
  • API-Datei konnte nicht analysiert werden "frameworks / base / api / current.txt"
  • Base64 kodieren Audiodatei und senden als String dann decodieren die String
  • Was ist ein Binder Callback auf Android?
  • Ist google-services.json vertraulich?
  • Moshi moshi = new Moshi.Builder() .add(new UserAdapter()) .build(); 

    Hier ist meine Implementierung von UserAdapter. Ich weiß, es ist Dummy, aber es funktioniert auch nicht so:

     public class UserAdapter { @FromJson User fromJson(String userJson) { Moshi moshi = new Moshi.Builder().build(); try { JSONObject jsonObject = new JSONObject(userJson); String accountType = jsonObject.getString("type"); switch (accountType) { case "Child": JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class); return childJsonAdapter.fromJson(userJson); case "Parent": JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class); return parentJsonAdapter.fromJson(userJson); } } catch (JSONException | IOException e) { e.printStackTrace(); } return null; } @ToJson String toJson(User user) { Moshi moshi = new Moshi.Builder().build(); JsonAdapter<User> jsonAdapter = moshi.adapter(User.class); String toJson = jsonAdapter.toJson(user); return toJson; } 

    Zuerst bekomme ich folgende Ausnahme mit diesem Code.

     com.squareup.moshi.JsonDataException: Expected a string but was BEGIN_OBJECT at path $.user 

    Und zweitens glaube ich, dass es einen besseren Weg gibt, es zu tun. Bitte Ratschläge

    Aktualisieren Hier ist Stacktrace für den Fehler:

      com.squareup.moshi.JsonDataException: Expected a name but was BEGIN_OBJECT at path $.user at com.squareup.moshi.JsonReader.nextName(JsonReader.java:782) at com.squareup.moshi.ClassJsonAdapter.fromJson(ClassJsonAdapter.java:141) at com.squareup.moshi.JsonAdapter$1.fromJson(JsonAdapter.java:68) at com.squareup.moshi.JsonAdapter.fromJson(JsonAdapter.java:33) at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:33) at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:23) at retrofit.OkHttpCall.parseResponse(OkHttpCall.java:148) at retrofit.OkHttpCall.execute(OkHttpCall.java:116) at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:111) at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:88) at rx.Observable$2.call(Observable.java:162) at rx.Observable$2.call(Observable.java:154) at rx.Observable$2.call(Observable.java:162) at rx.Observable$2.call(Observable.java:154) at rx.Observable.unsafeSubscribe(Observable.java:7710) at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62) at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818) 

  • Wie lese ich die Kontaktliste?
  • Das Json-Array kann nicht mit Gson analysiert werden
  • HashMap zu ListView
  • So suchen Sie nach einem Wert in Firebase Android
  • Wie kann ich verhindern, dass Android Activity kurz in den Portrait-Modus gelangt, wenn ich die Landschaft angegeben habe?
  • Erkennung von AC (Ein / Aus) und Fenster (Öffnen / Schließen) von CAR mit OBD
  • 2 Solutions collect form web for “Benutzerdefinierter Konverter zur Unterklasse mit Moshi”

    Dies scheint mir wie das Beispiel, das Sie für Ihre benutzerdefinierte De / Serialisierung Ihrer JSON Daten folgen wollen: https://github.com/square/moshi#another-example

    Es verwendet eine Zwischenklasse, die der JSON-Struktur entspricht, und Moshi wird es automatisch für Sie aufblasen. Dann können Sie die aufgeblasenen Daten verwenden, um Ihre Fachklassen zu erstellen. Beispielsweise:

     // Intermediate class with JSON structure class UserJson { // Common JSON fields public String type; public String name; // Parent JSON fields public String occupation; public Long salary; // Child JSON fields public String favorite_toy; public Integer grade; } abstract class User { public String type; public String name; } final class Parent extends User { public String occupation; public Long salary; } final class Child extends User { public String favoriteToy; public Integer grade; } 

    Jetzt ist der Adapter:

     class UserAdapter { // Note that you pass in a `UserJson` object here @FromJson User fromJson(UserJson userJson) { switch (userJson.type) { case "Parent": final Parent parent = new Parent(); parent.type = userJson.type; parent.name = userJson.name; parent.occupation = userJson.occupation; parent.salary = userJson.salary; return parent; case "Child": final Child child = new Child(); child.type = userJson.type; child.name = userJson.name; child.favoriteToy = userJson.favorite_toy; child.grade = userJson.grade; return child; default: return null; } } // Note that you return a `UserJson` object here. @ToJson UserJson toJson(User user) { final UserJson json = new UserJson(); if (user instanceof Parent) { json.type = "Parent"; json.occupation = ((Parent) user).occupation; json.salary = ((Parent) user).salary; } else { json.type = "Child"; json.favorite_toy = ((Child) user).favoriteToy; json.grade = ((Child) user).grade; } json.name = user.name; return json; } } 

    Ich denke, das ist viel sauberer und erlaubt Moshi, seine Sache zu tun, die Objekte von JSON schafft und JSON aus Objekten schafft. Kein JSONObject mit altmodischem JSONObject !

    Zu testen:

     Child child = new Child(); child.type = "Child"; child.name = "Foo"; child.favoriteToy = "java"; child.grade = 2; Moshi moshi = new Moshi.Builder().add(new UserAdapter()).build(); try { // Serialize JsonAdapter<User> adapter = moshi.adapter(User.class); String json = adapter.toJson(child); System.out.println(json); // Output is: {"favorite_toy":"java","grade":2,"name":"Foo","type":"Child"} // Deserialize // Note the cast to `Child`, since this adapter returns `User` otherwise. Child child2 = (Child) adapter.fromJson(json); System.out.println(child2.name); // Output is: Foo } catch (IOException e) { e.printStackTrace(); } 

    Sie haben wahrscheinlich versucht, Sie zu analysieren, wie folgt : https://github.com/square/moshi#custom-type-adapters

    Es wird String als Argument der @FromJson-Methode verwendet, also kann es magisch zu einer Mapping Helper-Klasse oder String analysiert werden und wir müssen es manuell analysieren, richtig? Eigentlich nein, du kannst entweder Mapping Helper Klasse oder Map verwenden.

    Also Ihre Ausnahme Expected a string but was BEGIN_OBJECT at path $.user wurde von Moshi versucht, diesen Benutzer als String zu bekommen (weil das ist, was Sie in Ihrem Adapter impliziert), während es nur ein anderes Objekt ist.

    Ich mag es nicht, alle möglichen Felder zu einer Helfer-Klasse zu analysieren, wie im Falle von Polymorphismus, dass die Klasse sehr groß werden könnte und Sie müssen sich verlassen oder sich daran erinnern / kommentieren Code.

    Sie können es als eine Karte behandeln – das ist Standard-Modell für unbekannte Typen – und konvertieren es in json, also in Ihrem Fall das würde so aussehen wie:

      @FromJson User fromJson(Map<String, String> map) { Moshi moshi = new Moshi.Builder().build(); String userJson = moshi.adapter(Map.class).toJson(map); try { JSONObject jsonObject = new JSONObject(userJson); String accountType = jsonObject.getString("type"); switch (accountType) { case "Child": JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class); return childJsonAdapter.fromJson(userJson); case "Parent": JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class); return parentJsonAdapter.fromJson(userJson); } } catch (JSONException | IOException e) { e.printStackTrace(); } return null; } 

    Natürlich kannst du einfach die Karte direkt bearbeiten: "type" String abrufen und dann den Rest der Karte in die gewählte Klasse analysieren. Dann gibt es keine Notwendigkeit, JSONObject überhaupt mit nettem Nutzen zu verwenden, nicht von Android abhängig zu sein und leichteres Testen des Parsing.

      @FromJson User fromJson(Map<String, String> map) { Moshi moshi = new Moshi.Builder().build(); try { String userJson = moshi.adapter(Map.class).toJson(map); switch (map.get("type")) { case "Child": JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class); return childJsonAdapter.fromJson(userJson); case "Parent": JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class); return parentJsonAdapter.fromJson(userJson); } } catch (IOException e) { e.printStackTrace(); } return null; } 
    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.