Nested JSON in Java ansprechen [Wordpress Rest Api]

chelayos

Mitglied
Pro JSONObjekt erstelle ich eine Map. Jedoch bei "replies" funktioniert dies nicht. Ich vermute, dies liegt daran, weil es ein JSONArray ist. Siehe dazu [Bild]: generiertes JSON von WP-API.

Java:
     String url = "https://studyhard.tk/wp-json/wp/v2/posts/"+id+"?_embed=1";

        final StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                gson = new Gson();

                mapPost = (Map<String, Object>) gson.fromJson(s, Map.class);
                mapTitle = (Map<String, Object>) mapPost.get("title");
                mapContent = (Map<String, Object>) mapPost.get("content");
                map_embedded = (Map<String, Object>) mapPost.get("_embedded");

                // Do we have replies?
                if(map_embedded.containsKey("replies"))
                {
                    map_replies = (Map<String, Object>) map_embedded.get("replies"); // Error
                }

map_replies = Map<String, Object>
map_replies = Map<String, Array>
map_replies = Map<String, ArrayList>
map_replies = Map<String, ArrayList<Object>>
map_replies = Map<String, ArrayList<JSONObject>>
map_replies = Map<String, JSONArray>
map_replies = Map<String, List<Object>>
map_replies = Map<String, List<JSONObject>>
map_replies = Map<String, List<JSONArray>>
Ist dies überhaupt möglich mit Map? Oder kennt ihr einen besseren Datentyp, damit ich auf "replies" zugreifen kann?
 
Wenn du eh GSON nutzt, bau dir das JSON-Objekt als normales Java-Objekt nach.

also etwa:
Java:
class Post {//Namen und Typen etwas geraten...
int id;
LocalDateTimt date;
//...
Embedded _embedded;
}

class Embedded {//Namen und Typen etwas geraten...
List<Author> author;
List<Reply> replies;//wenn da Liste passt, uU List<List<...>>?
//...
}

Ansonsten, "replies" ist eine Liste, keine Map
 
Zuletzt bearbeitet:
Das Problem ist, ich kann nur Klassen mit "Object" machen:

Java:
public class WPPost {
    public Object id;
    public Object title;
}

Wenn ich int id oder string title verwende stürzt es ab.
Code:
FATAL EXCEPTION: main
                                                                      Process: tk.studyhard.android, PID: 15861
                                                                      com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 11

Wenn ich nun den Titel als Object ausgebe
Java:
wp = (WPPost) gson.fromJson(s, WPPost.class);
content.loadData(wp.title.toString(),"text/html; charset=UTF-8", null);
kommt das:
{rendered=Willkommen bei Wordpress}
Aber ich benötige nur den Teil Willkommen bei Wordpress
 
Oder das Objekt passend nachbauen. Titel zB ist kein String, sondern ein Objekt, welches du dann auch repräsentieren müsstest.
 
Mit einer gewöhnlichen ArrayList (ohne Map) scheint es zu funktionieren.
Java:
// Do we have replies?
                if(map_embedded.containsKey("replies"))
                {
                    map_replies = (ArrayList) map_embedded.get("replies");
                    content.loadData(map_replies.toString(), "text/html; charset=UTF-8", null);
                }

Code wurde ebenfalls auf Github aktualisiert.

der Output:
t1.png


Ich benötige folgende Felder:
  • content
  • author_name
  • date
Gibts da nen besseren Weg als einfach die ganze Arraylist abzusuchen?
Ich habe weiter oben im Code Maps verwendet, weil das beim Postcontent so einfach ging:
mapContent.get("rendered").toString();
So wird nur der Inhalt ohne das {rendered=} ausgegeben. Gibts sowas ähnlcihes auch bei Arraylist?

@RalleYTN , @mrBrown Danke für eure Mitarbeit!
@mrBrown wie meinst du ein Objekt nachbauen / repräsentieren? Sorry steh grad aufm Schlauch. Evtl Beispiel wäre gut^^
 
Zuletzt bearbeitet:
Habe nun deinen Rat befolgt und habe Klassen erstellt:

Java:
public class WPPost {
    Map<String, Object> title;
    Map<String, Object> content;
    Embedded _embedded;
}

Java:
public class Embedded
{
    //Object[] replies;
//Object replies
    //ArrayList<Reply>[] replies;
//Arraylist<Reply> replies;
//List<Reply> replies;
    List<Reply>[] replies;
}

Java:
public class Reply
//Map<String, Object> author_name;
    //Map<String, Object> date;
    //Map<String, Object> content;
    String author_name;
    String date;
    String content;

Im Code kann ich nun bis zu _embedded zugreifen. Aber ich werde aber nicht schlau draus, wie es nun weiter gehen soll. Klar ich muss ich replies als Klasse nachbauen aber das funktioniert bis jetzt noch nicht. Habe verschiedene Dateitypen versucht (auch mit []) aber ich krieg nur Fehler oder Count: 0, wenn ich items zähle.
reply.png
 
Dann zeig doch mal die Fehlermeldung, die du bei welchem DatenTyp bekommst.

Entweder List<Reply> oder List<List<Reply>> müsste passen (sieht zumindest in dem Screenshot so aus...)
 
Guck dir einfach mal die Rückgagetypen bzw die Objekte selbst an, daraus und aus der Exception sollte das eig klar werden 😉

Generell, wenn du bei sowas casten musst ist was falsch gelaufen 😉
 
Bin nun soweit, dass Kommentare dargestellt werden 😀*Freudensprung*
output.png


Ich habe das Datum auf das deutsche Format dd.MM.yy umgewandelt. Sieht mir persönlich aber zu kompliziert aus. Macht man das so in Java oder geht das doch einfacher?

Java:
   String content = "";

                SimpleDateFormat formatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                SimpleDateFormat formatter2 = new SimpleDateFormat("dd.MM.yy");

                for (Replies r : wp._embedded.replies[0])
                {
                    try
                    {
                        content += formatter2.format(formatter1.parse(r.date));
                    }
                    catch(ParseException e)
                    {
                        //invalid date
                    }
                    content += " " + r.author_name + ": ";
                    content += r.content.get("rendered");
                }
                content= content.replaceAll("<p>", "");
 
Moin,
Ich habe das Datum auf das deutsche Format dd.MM.yy umgewandelt. Sieht mir persönlich aber zu kompliziert aus
Wieso kompliziert ??

Macht man das so in Java oder geht das doch einfacher?
Was genau ist bei r.date das date??
Nutzt Du Java8 oder ist hier noch das als depricated gekennzeichnete date der älteren Version im Einsatz?

Aber setz' dich ggf. mal mit der LIB JodaTime auseinander, die ist deutlich komfortabler !
http://www.joda.org/joda-time/

Gruß Klaus
 
Nutzt Du Java8 oder ist hier noch das als depricated gekennzeichnete date der älteren Version im Einsatz?
Date ist nicht Deprecated.
___

Am einfachsten wäre, den Feldern passende Datentypen zu geben (nicht String für ein Datum!), und dem GSON-Parser den passenden DateFormatter zuzuweisen, dann musst du's nur noch einmalig für die Ausgabe parsen.
 
Aber gerne doch 🙂

Geh' links oben auf java.util, dann unten auf Date ....
Da sind dann alle (bis einen) Konstruktoren depricated, und das Gros der Methoden !

Gruß Klaus
 
Date als ganzes ist (noch?) nicht deprecated, aber dafür jede zweite Methode davon, was meiner Meinung nach ein gutes Indiz gegen die Nutzung davon ist.
Die sinds auch schon seit einigen JDK-Versionen (min 1.5, und seit 1.1 gibts zumindest Ersatz dafür), deshalb würd ich erstmal nicht davon ausgehen, dass es so schnell kommt, auch wenn ich sehr dafür wäre, wenn es eher heute als morgen passiert 😉


Sinnvoll wäre es hier auf jeden Fall, da LocalDate zu benutzen (wenn das nicht also komplex ist, GSON das beizubringen...)
 
Die sinds auch schon seit einigen JDK-Versionen (min 1.5, und seit 1.1 gibts zumindest Ersatz dafür), deshalb würd ich erstmal nicht davon ausgehen, dass es so schnell kommt, auch wenn ich sehr dafür wäre, wenn es eher heute als morgen passiert 😉
richtig, des wegen wollte ich anfangs auch "Versionen" schreiben - das "en" am Ende ist wohl bei der Wärme weggeschmolzen 😀

Wie nutzen hier seit längerem nur noch das oben erwähnte JodaTime, was IMHO wesentlich eleganter ist!

Allerdings es seit Java8 ja eine ganz neue Klasse, die ich aber auch noch nicht ausprobiert habe ...
http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html
https://kevcodez.de/index.php/2015/07/java-8-date-und-time-api-neue-datumsfunktionen/

Gruß Klaus
 
Wie nutzen hier seit längerem nur noch das oben erwähnte JodaTime, was IMHO wesentlich eleganter ist!

Allerdings es seit Java8 ja eine ganz neue Klasse, die ich aber auch noch nicht ausprobiert habe ...
http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html
https://kevcodez.de/index.php/2015/07/java-8-date-und-time-api-neue-datumsfunktionen/
Die neue Date-API ist ja auch nach JodaTime-Vorbild entstanden, dürfte also ähnlich gut zu benutzen sein, und hat zusätzlich den Vorteil, das es zur Standard-API gehört 😉
 
Wieso kompliziert ??
Weil ich 5 Zeilen brauche, nur um das Datum ins richtige Format zu bringen xD
Was genau ist bei r.date das date??
Das Feld date im JSON ist ein String. Beispiel:
"2016-03-15T02:25:15"
Ich habe ehrlich gesagt keine Ahnung. Ich verwende das neueste AndroidStudio mit der neuesten SDK (Android 7). JAVA/Android ist neu für mich. Komme eigentlich aus der C# Ecke.
hat zusätzlich den Vorteil, das es zur Standard-API gehört
Genau, deswegen könnte ich mir dies eher vorstellen zu benutzen. Ich möchte eigentlich keine/wenige Bibliotheken einsetzen, damit meine Androidapp nicht so gross wird.

Noch ne allgemeine Frage. Ich habe vor z.B. oben links ein Menü zu integrieren mit Kategorien (von Wordpress). Ich habe sehe da folgende Möglichkeiten:

1) Hardkodieren / feste URLs setzen. Spart Zeit, da wenig Programmieraufwand. Ressourcenschonend. App startet schneller, da 1x Request weniger gesendet / geparst werden musst. Aber ich muss die App früher oder später anpassen, wenn es neue Kategorien gibt.

2.) Kategorien von Wordpress abgreifen. Somit müsste ich meine App nie wieder ändern.
Aber dann muss bei jedem Appstart noch die Kategorien via Request geholt werden.

3.) Die Premiumvariante währe wohl 2) mit Caching. z.B. 1x täglich bei Wordpress nachfragen, obs neue Kategorien gibt.
 
Weil ich 5 Zeilen brauche, nur um das Datum ins richtige Format zu bringen xD
Naja, eigentlich sinds nur 3 Zeilen, und mit passend konfiguriertem GSON sinds drei (bzw eine), kompliziert ist das noch nicht, wenig Zeilen sind selten besser als viele 😉

Das Feld date im JSON ist ein String. Beispiel:
"2016-03-15T02:25:15"
Lass wie gesagt GSON daraus ein Date machen, dann sparst du dir das.

Ich habe ehrlich gesagt keine Ahnung. Ich verwende das neueste AndroidStudio mit der neuesten SDK (Android 7). JAVA/Android ist neu für mich. Komme eigentlich aus der C# Ecke.
Genau, deswegen könnte ich mir dies eher vorstellen zu benutzen. Ich möchte eigentlich keine/wenige Bibliotheken einsetzen, damit meine Androidapp nicht so gross wird.

Dann fällt die Java 8-API weg, du wirst also entweder mit dem echt unschönen Date arbeiten müssen, oder externe libs einbinden müssen. JodaTime sollte nicht allzu groß sein.


Noch ne allgemeine Frage. Ich habe vor z.B. oben links ein Menü zu integrieren mit Kategorien (von Wordpress). Ich habe she da folgende Möglichkeiten:

1) Hardkodieren / feste URLs setzen. Spart Zeit, da wenig Programmieraufwand. Ressourcenschonend. App startet schneller, da 1x Request weniger gesendet / geparst werden musst. Aber ich muss die App früher oder später anpassen, wenn es neue Kategorien gibt.

2.) Kategorien von Wordpress abgreifen. Somit müsste ich meine App nie wieder ändern.
Aber dann muss bei jedem Appstart noch die Kategorien via Request geholt werden.

3.) Die Premiumvariante währe wohl 2) mit Caching. z.B. 1x täglich bei Wordpress nachfragen, obs neue Kategorien gibt.

Das ganze hinter einem Interface verpacken mit passende Factory z.B., dann kann man es erstmal hardcoded machen, und nachher immernoch an 2) oder 3) anpassen
 
Ist das nicht ziemliches POITROAE was Du da machst? Check doch erst einmal wie lange die Abfrage der Kategorien dauert. Weiterhin wäre die Premiumvariante eigentlich

Neustart der App:

Menu ist leer. Du startest einen Background-Task. Dieser holt die Kategorien und setzt sie ins Menu und speichert sie in einer propeties datei.

alle weiteren Starts:

Laden der Menus aus der property Datei und anzeigen. Gleichzeitig im Background Task die Kategorien holen und wenn fertig in property datei speichern und menu aktualiseren.

Das ist auch nicht wirklich schwer zu implementieren.

Gruß

Claus
 

Zurück
Oben