2012-10-31 7 views
5

ich Flexjson verwenden ist derzeit versucht, Zuordnen eines JSON String deserialisieren und es auf das Objektmodell meines Android App kartieren. Die Anwendung ist eine Art Bibliothek mit mehreren Anbietern, die einige Kataloge mit mehr Katalogen und Dokumenten in ihnen haben können. Die json geholt von einem Web-Service, den ich keinen Einfluss haben auf und sieht etwa so aus:eine JSONObject auf eine Liste mit Flexjson in Java/Android

{ 
    "library":{ 
     "vendor":[ 
      { 
       "id":146, 
       "title":"Vendor1", 
       "catalog":[ 
        { 
         "id":847, 
         "document":[ 
          { 
           "id":1628, 
           "title":"Document", 
       ... 
          }, 
          { 
       ... 
          } 
         ], 
         "title":"Catalog ", 
        }, 
       { 
       ... 
       } 
       ] 
      }, 
      { 
      ... 
      } 
     ] 
    } 
} 

So jeder Anbieter, Katalog, Dokument von einem JSONObject und alle untergeordneten Kataloge und Dokumente sind innerhalb eines JSONArray vertreten ist. Bisher funktioniert alles mit Flexjson in Ordnung und der folgenden Deserialisierung Code:

LibraryResponse response = new JSONDeserializer<LibraryResponse>() 
        .use(Timestamp.class, new TimestampObjectFactory()) 
        .deserialize(getLocalLibrary(), LibraryResponse.class); 
return response.library; 

Ich habe eine Bibliothek Objekt, das eine List<Vendor> hat. Jeder Lieferant hat eine List<Catalog> und eine List<Document>.

Leider bindet der Webservice die JSONArrays an einfache JSONObjects, wenn ein Katalog nur ein einziges Dokument enthält oder ein Katalog nur einen Katalog enthält. So ist die json in diesem Fall wie folgt aussieht:

"document": 
    { 
     "id":1628, 
     "title":"Document", 
     ... 
    } 

Jetzt Flexjson weiß nicht, wie deserialisieren und ich am Ende mit einem library.vendorX.getDocument() ein List<HashMap> anstelle ein List<Document> zu sein. Eine Idee ist, Flexjson explizit zu erklären, wie man mit solchen Fällen umgeht, aber ich habe keine Ahnung, wo ich damit anfangen soll. Ein anderer Weg könnte darin bestehen, das anfängliche json manuell zu analysieren und solche JSONObjects durch das entsprechende JSONArray zu ersetzen. Aber ich denke, dass es nicht schön ist, dorthin zu gehen, da die Bibliothek ziemlich tief sein kann.

Ich hoffe, Sie können hier eine Anleitung geben.

Antwort

1

Yikes dies ist einige gnarly Json Mapping weiter. Welcher Backend-Codierer hat das getan ?! #Nicht helfend.

Nun, wenn man sich den Code ansieht, ist Flexjson so programmiert, dass er sofort einsatzbereit ist. Aber es sieht so aus, als ob es die Typisierungsinformationen nicht an die Bindung weitergibt, so dass es nicht weiß, an welchen Typ es bindet, so dass es nur eine Map zurückgibt. Das ist ein Bug, der wahrscheinlich behoben werden sollte. Gute Nachrichten gibt es eine Arbeit um.

Wie auch immer, die einfachste Sache, die ich mir vorstellen kann, ist die Installation einer ObjectFactory auf dieser Liste. Dann können Sie überprüfen, ob Sie eine Map oder eine Liste erhalten, wenn der Stream deserialisiert wird. Dann können Sie es in eine Liste einfügen und an den entsprechenden Decoder senden. Etwas wie:

LibraryResponse response = new JSONDeserializer<LibraryResponse>() 
       .use(Timestamp.class, new TimestampObjectFactory()) 
       .use("library.vendor.values.catalog.values.document", new ListDocumentFactory()) 
       .deserialize(getLocalLibrary(), LibraryResponse.class); 

Dann

public class ListDocumentFactory implements ObjectFactory { 

    public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) { 
     if(value instanceof Collection) { 
      return context.bindIntoCollection((Collection)value, new ArrayList(), targetType); 
     } else { 
      List collection = new ArrayList(); 
      if(targetType instanceof ParameterizedType) { 
       ParameterizedType ptype = (ParameterizedType) targetType; 
       collection.add(context.bind(value, ptype.getActualTypeArguments()[0])); 
      } else { 
       collection.add(context.bind(value)); 
       return collection; 
      } 
     } 
    } 
} 

Ich denke, das ist ungefähr das, was diesen Fehler zu beheben wäre, sollte aber auch Ihr Problem beheben.

+0

Danke für Ihre Antwort! Ich denke, ich habe mich nicht klar gemacht, ich bekomme immer eine Liste, aber für den Fall, dass es nur ein Dokument gibt, habe ich keine 'Dokumente' in der Liste, sondern 'HashMaps', also' List ' als 'Katalog.document' statt 'Liste '. Die Hash-Map-Objekte enthalten die Daten, die mit dem Dokument verbunden sind. Es kommt mir seltsam vor. Ich denke, ich brauche eine Fabrik, die entscheidet, ob wir bereits ein Dokument haben oder eine HashMap haben. Wenn letzteres würde ich das Dokumentobjekt manuell zuordnen.Meine ersten Versuche scheiterten jedoch. Denken Sie, dass dieser Ansatz möglich ist? –

+0

Ich sehe nicht, wie meine Antwort Ihr Problem nicht beantwortet hat. Ich denke, der Grund, warum Sie eine Liste statt Liste bekommen, ist ein Fehler in Flexjson. JSONDeserializer übersetzt das JSON zuerst in einfache Objekte wie Liste, Map, String, Zahl und Boolean. Dann verwendet es eine Reihe von ObjectFactory, um diese einfachen Objekte den tatsächlichen Objekten zuzuordnen, in die Sie mappen. Also ist der ObjectFactory-Layer bevor wir irgendein stark typisiertes Objekt wie Document haben. Sie werden sich also an diesen Punkt anschließen und Ihre eigene ObjectFactory schreiben, wie ich es gezeigt habe, anstatt die Standardinstanz zu verwenden. – chubbsondubs

+0

Es tut mir leid, ich glaube ich habe dich dort missverstanden. Wie auch immer, wenn ich Code versuche, erhalte ich eine Exception bei 'ParameterizedType ptype = (ParameterizedType) targetType;' 'java.lang.ClassCastException: java.lang.Class kann nicht in java.lang.reflect.ParameterizedType' umgewandelt werden. Noch eine Frage: Wenn ich die Factory für 'library.vendor.values.catalog.values.document' festlege, hat das keine Auswirkungen auf andere Ebenen als' library.vendor.values.document'? Da sogar ein Anbieter Dokumente haben kann ... Wäre es möglich, die Factory anzugeben, die in 'LibraryItem.class' verwendet werden soll, welche die Oberklasse aller anderen ist? –

Verwandte Themen