Java FX JsonObjekt Children auslesen

iso66

Mitglied
Hallo liebes Forum,

ich hab folgenden Java Code:
Java:
public void generatejson(File file, Object stage) {

		
	try {
		JSONObject object = (JSONObject) new JSONParser().parse(new FileReader(file));
			
		JSONObject child = new JSONObject();
		child.get(child);
			
		for(int i=0;i<child.size(); i++){
			@SuppressWarnings("unused")
			JSONArray children= (JSONArray) child.get(i);
			System.out.println("Kind1 Children\n" + child);
		}
			
			
		} catch (Exception e) {
			e.printStackTrace();
	
		}
		// This implies that the first token in JsonToken.BEGIN_OBJECT, which is always true.
		// handleObject(reader);

	}

Mein Problem ist, ich will die Kinder von dem JsonObjekt, den ich in Line 6 erstelle habe, Rekursiv und einzeln an meiner Console anzeigen lassen. Also am Anfang nur die Kinder, danach die Kindes Kinder.
Ich glaube, dass ich ab Line 8 - 16 nicht ganz richtig ist, weil die geöffnete Json-Datei nebeneinander auf meiner Console angezeigt wird.

Bitte um Hilfe.
 
Falsches Unterforum, aber ich antworte mal trotzdem 🙂

So. Also. Naja, für Rekursion brauchst du auch eine sich wieder selbst aufrufende Methode, oder? ;-)

Erster Fehler:
Zeile 9
child.get(child);

Ich denke du willst
JSONObject child = object.getJSONObject("my-object"); // ersetze "my-object" mit einem richtigen Namen

Frage meinerseits: Hat das Json ein festes Format? Wird es immer das Gleiche sein? Wenn ja, verwende einen Objektrelationalen Mapper wie jackson, gson oder so.
Vorteil: Du erhälst ordentliche Java-Beans. Musst dich also nicht so "Low-Level" durch den Json-Baum hangeln.
Nachteil: Etwas höherer Memory-Footprint (glaube ich zumindest) und "nicht so flexibel". Manchmal genügt dein Ansatz, aber ich mach das nur im "Notfall".
 
Danke für deine Antwort Dzim,
Also. Naja, für Rekursion brauchst du auch eine sich wieder selbst aufrufende Methode, oder?

Ich hab es nun so gemacht Dzim:
Java:
try {
			JSONObject parent = (JSONObject) new JSONParser().parse(new FileReader(file));

			// First Key zeigt die Parents an
			for (Object key : parent.keySet()) {
				System.out.println(key);

				JSONObject child1 = (JSONObject) parent.get(key); // Show Parent keys

				// Second Key key2:child1 first child -->
				for (Object key2 : child1.keySet()) {
					System.out.println("    " + key2);

					Object child2 = child1.get(key2); // Child 2 kommt unter child 1

}
}
}

So lass ich mir den Tree, schritt für schritt an der Console ausgeben, jedoch wie du gemeint hast, was fehlt ist Rekursiv Methode.

Frage meinerseits: Hat das Json ein festes Format?
Ich habe einen festes Format, jedoch wird es nicht immer das selbe Json-Format sein.
Hab mir auch überlegt ob ich den Jackson Mapper nehmen soll, ist es besser?
 
Besser... Darüber lässt sich streiten. Einfacher? Auf jeden Fall. Du wirst das Format nicht alle Nase lang ändern (ausser vielleicht in der Design-Phase), somit ist es langfristig einfacher. Und Im Code ist dir auch immer schneller klar, was wo und warum passiert.

Bezüglich der Rekursion: Rekursion ist nicht, Schleifen zu schachteln! Rekursion ist, wenn sich eine Methode selbst aufruft - und idealerweise gemäss Divide & Conquer - ein Problem zerlegt und verarbeitet.

Unfertiger Java-Pseudo-Code sähe in etwa so aus (aus dem Gedächtnis, keine Lust zu Ende zu schreiben :-D )
[Java]
private void callPrintJson(JSONObject root) {
printJson(0, root);
}

private void printJson(int level, JSONObject node) {
for (String key : node.keySet()) {
if (value == (String||boolean||double||long||int)) { // pseudo code
// print
} else if (value == JSONObject) {
printJson(level+1, value);
} else if (value == JSONArray) {
// iterate over values,
// if JSONObject: printJson(level+1, value);
}
}
}
[/Java]

Etwa klar, was ich meine?
 
Nope. Wollte erst eine rekursive #toString-Methode machen, war mir dann abends aber doch zu viel und ich hab sie nur nicht umbenannt... 🙂
 
Guten morgen,
ich hab folgenden Code:
Java:
public class Convert{

public void generatejson(File file, Object stage) {
		
		
		try {
			JSONObject parent = (JSONObject) new JSONParser().parse(new FileReader(file));
			
			
			// First Key zeigt die Parents an
			for (Object key : parent.keySet()) {
				System.out.println(key);

				JSONObject child1 = (JSONObject) parent.get(key); // Show Parent keys

				// Second Key key2:child1 first child -->
				for (Object key2 : child1.keySet()) {
					System.out.println("	" + key2);

					Object child2 = child1.get(key2); // Child 2 kommt unter child 1

					// Laufzeitüberprüfung prüfung ob kombatibel ist.
					if (child2 instanceof JSONObject) {
						JSONObject child2a = (JSONObject) child2;
					} else if (child2 instanceof String) {
						System.out.println("    " + "		" + child2);
					}
				}

			}
}
}
}

Ich bekomme diesen Code, nicht Rekursive, könntet ihr mir bitte helfen bin am verzweifeln.
 
Bin verwirrt: Was willst du mit dem Code erreichen? JSON generieren (Java->JSON, der Name der Methode suggeriert das), oder parsen (also JSON->Java)?
 
Dann willst du parsen, nicht generieren.

Parsen = JSON -> Java
Generieren = Java -> JSON

Beispiel des Parsings mit Jackson:
https://github.com/FasterXML/jackson

Hier noch ein kleines Tutorial:
How to convert Java object to / from JSON (Jackson)

Beispiel (nutz aber noch die alte Version 1.9.11):

Modell
Java:
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class Manifest {
	
	private List<ManifestEntry> files;
	
	private String version;
	private String revision;
	private Boolean required;
	private String hash;
	
	public List<ManifestEntry> getFiles() {
		if (files == null) {
			files = new ArrayList<ManifestEntry>();
		}
		return files;
	}
	
	public String getVersion() {
		return version;
	}
	
	public void setVersion(String version) {
		this.version = version;
	}
	
	public String getRevision() {
		return revision;
	}
	
	public void setRevision(String revision) {
		this.revision = revision;
	}
	
	public Boolean getRequired() {
		return required;
	}
	
	public void setRequired(Boolean required) {
		this.required = required;
	}
	
	public String getHash() {
		return hash;
	}
	
	public void setHash(String hash) {
		this.hash = hash;
	}
}
Java:
public class ManifestEntry {
	
	private String hash;
	private String file;
	private Long size;
	
	public ManifestEntry() {}
	
	public String getHash() {
		return hash;
	}
	
	public void setHash(String hash) {
		this.hash = hash;
	}
	
	public String getFile() {
		return file;
	}
	
	public void setFile(String filename) {
		this.file = filename;
	}
	
	public Long getSize() {
		return size;
	}
	
	public void setSize(Long size) {
		this.size = size;
	}
}

Parser (nur Methoden):
Java:
	public static synchronized Manifest readManifest(File source) throws JsonParseException, JsonMappingException, FileNotFoundException, IOException {
		Manifest mf = null;
		org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
		// wenn der root eine Liste ist:
		// mapper.readValue(new FileInputStream(source),mapper.getTypeFactory().constructCollectionType(List.class,ManifestEntry.class));
		// ansonsten direkt die Klasse angeben
		mf = mapper.readValue(new FileReader(source), Manifest.class);
		return mf;
	}
	
	public static synchronized void writeManifest(File target, Manifest mf) throws JsonGenerationException, JsonMappingException,
			FileNotFoundException, IOException {
		if (target == null || mf == null) {
			return;
		}
		org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
		// wenn der root eine Liste ist:
		// mapper.writeValue(new FileOutputStream(target,false),mf.getFiles());
		// ansonsten direkt die Klasse angeben
		mapper.writeValue(new FileOutputStream(target, false), mf);
	}

Code:
{
  "files":[
    {"hash":"/BRhU+4aPDhUT3g6kce9hJQjFBtfElyQLNjdmTJqSmE=","file":"appFX-0.10.0.jar","size":768954},  
    {"hash":"VJitYa+NmYQnup55wTcRWhGe8Q4jqxsv4qmCLA8EMnU=","file":"libs/sqlite-jdbc-3.8.7.jar","size":3964244},  
    {"hash":"E2iUGODXO4WGW4PAOcpXCd2JRO2BFItJA1UVq71y+n0=","file":"libs/jackson-all-1.9.11.jar","size":1147899}
  ],
  "version":"0.10.0",
  "revision":"3545647",
  "required":null,
  "hash":"jP2T6k7D8c8rwpH6oeezIAGUGD+yclM4icVKUNgcxhw="
}

That's it.
 
Zuletzt bearbeitet:
Ich muss den Code, den ich vorhin gepostet habe rekursive schreiben Dzim, so das ich an meiner Console, mit println einen Tree Form für mich anzeigen lassen kann. Das ist mein Problem, dass ich den Code nicht rekursive bekomme.
Parsen und das ganze funktioniert bei mir.
 
Da ich nicht weiss, welche Bibliothek du nutzt: Ich habe das erste von der Liste bei json.org für Java heruntergeladen und in ein Test-Projekt geworfen:

JSON --> https://github.com/douglascrockford/JSON-java

Java:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

public class JSONRecursive {
	
	public static void main(String[] args) throws IOException {
		JSONRecursive jsonRecursive = new JSONRecursive(new File(args[0]));
		jsonRecursive.doPrint();
	}
	
	private final File f;
	
	public JSONRecursive(File f) {
		this.f = f;
	}
	
	public void doPrint() throws IOException {
		Reader reader = new FileReader(f);
		JSONTokener tokener = new JSONTokener(reader);
		JSONObject object = new JSONObject(tokener);
		StringBuilder sb = new StringBuilder();
		printJsonObject(sb, 0, object);
		System.out.println(sb.toString());
		reader.close();
	}
	
	private void printJsonObject(StringBuilder sb, int level, JSONObject jsonObject) {
		sb.append(String.format("%s{%n", intent(level)));
		String[] names = JSONObject.getNames(jsonObject);
		for (int i = 0; i < names.length; i++) {
			String name = names[i];
			sb.append(String.format("%s'%s': ", intent(level + 1), name));
			Object o = jsonObject.get(name);
			printObject(sb, level + 1, o);
			if ((i + 1) < names.length) {
				sb.append(",");
			}
			sb.append("\n");
		}
		sb.append(String.format("%s}", intent(level)));
	}
	
	private void printObject(StringBuilder sb, int level, Object o) {
		if (o instanceof Boolean) {
			sb.append(String.format("%b", (Boolean) o));
		} else if (o instanceof Double) {
			sb.append(String.format("%f", (Double) o));
		} else if (o instanceof Integer) {
			sb.append(String.format("%d", (Integer) o));
		} else if (o instanceof Long) {
			sb.append(String.format("%d", (Long) o));
		} else if (o instanceof String) {
			sb.append(String.format("%s", (String) o));
		} else if (o instanceof JSONObject) {
			// Rekursion auf die obere Methode - weil ist einfacher so...
			printJsonObject(sb, level + 1, (JSONObject) o);
		} else if (o instanceof JSONArray) {
			// Rekursion auf diese Methode
			sb.append("[\n");
			JSONArray jsonArray = (JSONArray) o;
			for (int i = 0; i < jsonArray.length(); i++) {
				printObject(sb, level + 1, jsonArray.get(i));
				if ((i + 1) < jsonArray.length()) {
					sb.append(",");
				}
				sb.append("\n");
			}
			sb.append(String.format("%s]", intent(level)));
		}
	}
	
	private String intent(int level) {
		if (level == 0) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < level; i++) {
			sb.append("  ");
		}
		return sb.toString();
	}
}
produziert JSON-Formatierten Code (nicht unbedingt sinnvoll, wenn man bereits gleich formatierten Code hat, aber über Sinn und Unsinn kann man sich streiten... 🙂 ).

muss im Prinzip nur minimal angepasst werden um einen Baum darzustellen. Und alles einzeln auf die Konsole werfen muss man imho nicht (daher schleife ich auch die StringBuilder-Instanz immer durch - könnte man auch durch System.out.print(), bzw. System.out.printf() ersetzt werden).
 
Zuletzt bearbeitet:
Was jetzt nicht heisst, dass du es nicht lernen musst, zu verstehen! Das Beispiel ist klein genug, um es jedenfalls verstehen zu lernen.

BTW: Einige haben es in ihrer Signatur... Ich nicht. Dennoch: freu mich natürlich, wenn du an hilfreiche Posts von mir auch ein "Daumen hoch" gibst. Verbessert auch meine Statistik für Tops... 🙂
 
Dzim in Line 36 kann er mir den jsonobject garnicht finden, bekomm da den Fehler.

Java:
The method getNames(JSONObject) is undefined for the type JSONObject

und wenn ich jsonObject mache bekomm ich den Fehler
Java:
jsonObject cannot be resolved to a variable


Kannst du mir ein Tipp geben wie ich es verbessern kann bitte.
 
Du musst die richtige Bibliothek verwenden. Ich hatte es ja oben angemerkt: Ich habe die erste von der json.org-Seite verwendet:
JSON --> https://github.com/douglascrockford/JSON-java

Es gibt unzählige andere, die alle mehr oder weniger das gleiche machen. Diese war die erste simple, die mir untergekommen ist (und ist glaube ich auch so was wie die "offizielle", aber da hab ich keine Ahnung). Ich dieses Package nur aus Android (aber auch da ist es minimal anders).
 
Zuletzt bearbeitet:
hmm, komisch hab die simple packages probiert sowie auch den Android, von der Seite die du mir gepostet hast.
Nur im Line 36 bekomme ich den Fehler, ich den mal das der Fehler generell von getNames() kommt.
 
das ist eine statische Methode der Klasse JSONObject. Mehr kann ich dir darüber auch nicht sagen, ausser das die von GitHub sie eben hat. Lade doch einfach diese runter und nutze sie... Was hindert sich daran?
 
Falsches Unterforum, aber ich antworte mal trotzdem 🙂

So. Also. Naja, für Rekursion brauchst du auch eine sich wieder selbst aufrufende Methode, oder? ;-)

Erster Fehler:
Zeile 9
child.get(child);

Ich denke du willst
JSONObject child = object.getJSONObject("my-object"); // ersetze "my-object" mit einem richtigen Namen

Frage meinerseits: Hat das Json ein festes Format? Wird es immer das Gleiche sein? Wenn ja, verwende einen Objektrelationalen Mapper wie jackson, gson oder so.
Vorteil: Du erhälst ordentliche Java-Beans. Musst dich also nicht so "Low-Level" durch den Json-Baum hangeln.
Nachteil: Etwas höherer Memory-Footprint (glaube ich zumindest) und "nicht so flexibel". Manchmal genügt dein Ansatz, aber ich mach das nur im "Notfall".

Geht Deine Empfehlung auch bei anderen JavaFX Objekten, z. B. bei einem GridPane, eine Textfield setzen und davon den Namen holen?
Oder kann man den Namen des TextFields im Controller ändern?
@FXML private GridPane bGrid;
int row = 1;
private void bgrow() { // warum muss ich dies dynamisch machen, ich brauche nur je eine neue Zeile und die alten Textfelder müssen stehen bleiben
TextField zeile = new TextField();
buchungszeile.setEditable(true);
String hilf2 = String.valueOf(row-1);
zeile.setText(hilf2);
TextField posNr = new TextField();
TextField posNr = new TextField();
DatePicker datum2 = new DatePicker();
//pattern2 = Pattern.compile(regExDate);
datum2.setPromptText(pattern.toLowerCase());
datum2.setValue(null);
ComboBox Nr = new ComboBox(); //muss ComboBox werden
nr.setItems(kontNr);
nr.setEditable(true);
ComboBox auswahl = new ComboBox(); //muss ComboBox werden
auswahl.setItems(kontText);
TextField betragZeile = new TextField();
Button weitereRow = new Button();
weitereRow.prefWidth(180);
weitereRow.setText("Weitere Zeile");
weitereRow.setOnAction((EventHandler<ActionEvent>) new handleWeitereZeileEvent());
//ab zweiter Zeile
bGrid.addRow(row);
bGrid.add(zeile, 0, row);
bGrid.add(nr, 1, row);
bGrid.add(posNr, 2, row);
bGrid.add(datum2, 3, row);
bGrid.add(betragZeile, 4, row);
bGrid.add(waer, 5, row);
bGrid.add(text, 6, row);
bGrid.add(weitereRow, 7, row);
row = row+1;
// Meldung reseten
meldungT.setText("");


--
Und hier springe ich nun über den Button weitereRow und das ActionEvent noch einmal in die Methode bgrow rein, erzeuge also die gesamten Textfields noch einmal. Kann sie aber nicht auslesen, weil ich in einer anderen Methode die Namen der Textfields nicht habe.
 
Warum diesen uralt Thread ausgraben?

Geht Deine Empfehlung auch bei anderen JavaFX Objekten, z. B. bei einem GridPane, eine Textfield setzen und davon den Namen holen?
Oder kann man den Namen des TextFields im Controller ändern?
Was hat JSON mit JavaFX bzw. FXML Dateien zu tun?

Und hier springe ich nun über den Button weitereRow und das ActionEvent noch einmal in die Methode bgrow rein, erzeuge also die gesamten Textfields noch einmal. Kann sie aber nicht auslesen, weil ich in einer anderen Methode die Namen der Textfields nicht habe.
Füge deine Textfields zu einer Liste hinzu, dann kannst du auch später darauf zugreifen.
 
Ich fand dieses Beispiel und fand es interessant und dachte, wenn dies auch JavaFX geht, wäre es gut:
D. h. dynamisch TextFields erzeugen und von diesen die Namen auslesen, um mit ihnen zu arbeiten.
 

Zurück
Oben