Ich verwende die hier bereitgestellte JSON-Bibliothek http://www.json.org/java/index.html , um eine JSON- Zeichenfolge, die ich habe, in CSV zu konvertieren. Das Problem ist jedoch, dass die Reihenfolge der Schlüssel nach der Konvertierung verloren geht.
Dies ist der Konvertierungscode:
JSONObject jo = new JSONObject(someString);
JSONArray ja = jo.getJSONArray("items");
String s = CDL.toString(ja);
System.out.println(s);
Dies ist der Inhalt von "someString":
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
]
}
Das ist das Ergebnis:
WO,QU,WR,QA,NO
hasd,asd,qwe,end,qwer
Ich erwarte zwar, dass die Reihenfolge der Schlüssel eingehalten wird:
WR,QU,QA,WO,NO
qwe,asd,end,hasd,qwer
Gibt es eine Möglichkeit, dieses Ergebnis mit dieser Bibliothek zu erzielen? Wenn nicht, gibt es eine andere Bibliothek, die die Möglichkeit bietet, die Reihenfolge der Schlüssel im Ergebnis beizubehalten?
foo
vor Schlüsselbar
und manchmalbar
vorherfoo
. Dies macht es schwierig, Tests für zu schreiben.Antworten:
Es gibt (hackige) Möglichkeiten, dies zu tun ... aber Sie sollten es nicht tun.
In JSON wird ein Objekt folgendermaßen definiert:
Siehe http://json.org .
Die meisten Implementierungen von JSON bemühen sich nicht, die Reihenfolge der Name / Wert-Paare eines Objekts beizubehalten, da sie (per Definition) nicht signifikant ist.
Wenn Sie möchten, dass die Ordnung erhalten bleibt, müssen Sie Ihre Datenstruktur neu definieren. z.B
{ "items": [ [ {"WR":"qwe"}, {"QU":"asd"}, {"QA":"end"}, {"WO":"hasd"}, {"NO":"qwer"} ], ] }
oder einfacher:
{ "items": [ {"WR":"qwe"}, {"QU":"asd"}, {"QA":"end"}, {"WO":"hasd"}, {"NO":"qwer"} ] }
NACHVERFOLGEN
Sie müssen ein hartes Gespräch mit demjenigen führen, der diese Dateistruktur entworfen hat, und Sie dürfen sie nicht ändern. Es ist / sie sind einfach falsch. Sie müssen sie überzeugen.
Wenn sie dich das wirklich nicht ändern lassen:
So etwas ist wirklich schlimm. Einerseits verstößt Ihre Software gegen eine etablierte / langjährige Spezifikation, die die Interoperabilität fördern soll. Auf der anderen Seite verschmutzen die Trottel, die dieses lahme (nicht JSON!) Dateiformat entworfen haben, wahrscheinlich die Systeme anderer Leute usw., weil die Systeme ihren Unsinn nicht bewältigen können .
AKTUALISIEREN
Es lohnt sich auch zu lesen, was der JSON RFC (RFC 7159) zu diesem Thema sagt. Hier einige Auszüge:
quelle
Es ist ganz einfach, die Ordnung aufrechtzuerhalten. Ich hatte das gleiche Problem mit der Aufrechterhaltung der Reihenfolge von der DB-Schicht zur UI-Schicht.
Öffnen Sie die Datei JSONObject.java. Es verwendet intern HashMap, das die Reihenfolge nicht beibehält.
Ändern Sie es in LinkedHashMap:
//this.map = new HashMap(); this.map = new LinkedHashMap();
Das hat bei mir funktioniert. Lass es mich in den Kommentaren wissen. Ich schlage vor, dass die JSON-Bibliothek selbst eine andere JSONObject-Klasse haben sollte, die die Reihenfolge beibehält, wie JSONOrderdObject.java. Ich bin sehr arm bei der Auswahl der Namen.
quelle
this.map = new LinkedHashMap<String, Object>();
funktioniert immer noch nicht. Bitte helfen Sie?JSONObject.java
nimmt jede Karte, die Sie passieren. Es kann seinLinkedHashMap
oderTreeMap
und es wirdhashmap
nur dauern , wenn die Karte null ist.Hier ist der Konstruktor der
JSONObject.java
Klasse, der die Überprüfung der Karte durchführt.public JSONObject(Map paramMap) { this.map = (paramMap == null ? new HashMap() : paramMap); }
Bevor Sie also ein json-Objektkonstrukt erstellen
LinkedHashMap
und es dann wie folgt an den Konstruktor übergeben,LinkedHashMap<String, String> jsonOrderedMap = new LinkedHashMap<String, String>(); jsonOrderedMap.put("1","red"); jsonOrderedMap.put("2","blue"); jsonOrderedMap.put("3","green"); JSONObject orderedJson = new JSONObject(jsonOrderedMap); JSONArray jsonArray = new JSONArray(Arrays.asList(orderedJson)); System.out.println("Ordered JSON Fianl CSV :: "+CDL.toString(jsonArray));
Es besteht also keine Notwendigkeit, die
JSONObject.java
Klasse zu ändern . Hoffe es hilft jemandem.quelle
JSONObject
wird nicht als meine bestelltLinkedHashMap
. Benutzt duorg.json
lib?org.json
eine. Es definiert eineHashMap
interne, was auch immerMap
Sie ihm geben: @Deepak können Sie uns auf die Implementierung verweisen, die Sie verwendet haben?org.json
Bibliothek. Wenn Sie ein neuesJSONObject
Objekt erstellen und eine Karte als Argument übergeben, wird es immer in a konvertiertHashMap
. Der Konstruktor erstellt zunächst eine neue Karte:this.map = new HashMap<String, Object>();
und durchläuft dann Ihre Karte und kopiert jedes Element in seineHashMap
.Eine ausführlichere, aber allgemein anwendbare Lösung für diese Art von Problem besteht darin, zwei Datenstrukturen zu verwenden: eine Liste mit der Reihenfolge und eine Karte mit den Beziehungen.
Zum Beispiel:
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ], "itemOrder": ["WR", "QU", "QA", "WO", "NO"] }
Sie iterieren die itemOrder-Liste und verwenden diese, um die Kartenwerte nachzuschlagen. Die Bestellung bleibt erhalten, ohne Kludges.
Ich habe diese Methode oft verwendet.
quelle
Eine andere hackige Lösung mit Reflect:
JSONObject json = new JSONObject(); Field map = json.getClass().getDeclaredField("map"); map.setAccessible(true);//because the field is private final... map.set(json, new LinkedHashMap<>()); map.setAccessible(false);//return flag
quelle
Apache Wink hat JSONObject bestellt . Es behält die Reihenfolge beim Parsen des Strings bei.
quelle
Ich bin gerade auf dasselbe Problem gestoßen und glaube, dass die endgültige Lösung des Autors darin bestand, eine benutzerdefinierte ContainerFactory zu verwenden:
public static Values parseJSONToMap(String msgData) { JSONParser parser = new JSONParser(); ContainerFactory containerFactory = new ContainerFactory(){ @Override public Map createObjectContainer() { return new LinkedHashMap(); } @Override public List creatArrayContainer() { return null; } }; try { return (Map<String,Object>)parser.parse(msgData, containerFactory); } catch (ParseException e) { log.warn("Exception parsing JSON string {}", msgData, e); } return null; }
siehe http://juliusdavies.ca/json-simple-1.1.1-javadocs/org/json/simple/parser/JSONParser.html#parse(java.io.Reader,org.json.simple.parser.ContainerFactory)
quelle
Gelöst.
Ich benutzen die JSON.simple Bibliothek von hier https://code.google.com/p/json-simple/ den JSON - String zu lesen , die Reihenfolge der Tasten zu halten und verwenden JavaCSV Bibliothek von hier http://sourceforge.net/ Projekte / javacsv / zum Konvertieren in das CSV-Format.
quelle
org.json
, um zu konvertierenList<LinkedHahMap>
,JSONArray
um eine zu erstellenCSV
, dieCSV
erstellt wird, aber nicht in der gleichen Reihenfolge wie meineList
. Ich habe versucht, die beidenCSV
Bibliotheken zu verwenden, die Sie hier präsentieren, aber ich konnte die Methoden zum Konvertieren nicht finden. Könnten Sie bitte weitere Details angeben.Ich weiß, dass dies gelöst ist und die Frage vor langer Zeit gestellt wurde, aber da ich mich mit einem ähnlichen Problem befasse, möchte ich diesbezüglich einen völlig anderen Ansatz wählen:
Für Arrays heißt es: "Ein Array ist eine geordnete Sammlung von Werten." unter http://www.json.org/ - aber Objekte ("Ein Objekt ist eine ungeordnete Menge von Name / Wert-Paaren.") werden nicht geordnet.
Ich frage mich, warum sich dieses Objekt in einem Array befindet - das impliziert eine Reihenfolge, die nicht vorhanden ist.
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ] }
Eine Lösung wäre also, die Schlüssel in ein "echtes" Array zu legen und die Daten als Objekte zu jedem Schlüssel wie folgt hinzuzufügen:
{ "items": [ {"WR": {"data": "qwe"}}, {"QU": {"data": "asd"}}, {"QA": {"data": "end"}}, {"WO": {"data": "hasd"}}, {"NO": {"data": "qwer"}} ] }
Dies ist also ein Ansatz, der versucht, die ursprüngliche Modellierung und ihre Absicht zu überdenken. Aber ich habe nicht getestet (und ich frage mich), ob alle beteiligten Tools die Reihenfolge dieses ursprünglichen JSON-Arrays beibehalten würden.
quelle
In der realen Welt verfügt eine Anwendung fast immer über eine Java-Bean oder -Domäne, die zu / von JSON serialisiert / de-serialisiert werden soll. Es wurde bereits erwähnt, dass die JSON-Objektspezifikation keine Ordnung garantiert und eine Manipulation dieses Verhaltens die Anforderung nicht rechtfertigt. Ich hatte das gleiche Szenario in meiner Anwendung, in dem ich die Ordnung nur aus Gründen der Lesbarkeit aufrechterhalten musste. Ich habe die Standardmethode von Jackson verwendet, um meine Java-Bean in JSON zu serialisieren:
Object object = getObject(); //the source java bean that needs conversion String jsonString = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(object);
Um den JSON mit einem geordneten Satz von Elementen zu erstellen, verwende ich einfach die JSON-Eigenschaftsanmerkung in der Java-Bean, die ich für die Konvertierung verwendet habe. Ein Beispiel unten:
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"name","phone","city","id"}) public class SampleBean implements Serializable { private int id; private String name: private String city; private String phone; //...standard getters and setters }
das oben verwendete getObject ():
public SampleBean getObject(){ SampleBean bean = new SampleBean(); bean.setId("100"); bean.setName("SomeName"); bean.setCity("SomeCity"); bean.setPhone("1234567890"); return bean; }
Die Ausgabe zeigt gemäß der Annotation der Json-Eigenschaftsreihenfolge:
{ name: "SomeName", phone: "1234567890", city: "SomeCity", id: 100 }
quelle
Der sicherste Weg ist wahrscheinlich das Überschreiben der Schlüsselmethode, mit der die Ausgabe generiert wird:
new JSONObject(){ @Override public Iterator keys(){ TreeSet<Object> sortedKeys = new TreeSet<Object>(); Iterator keys = super.keys(); while(keys.hasNext()){ sortedKeys.add(keys.next()); } return sortedKeys.iterator(); } };
quelle
patchFor (Antwort @gary):
$ git diff JSONObject.java diff --git a/JSONObject.java b/JSONObject.java index e28c9cd..e12b7a0 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -32,7 +32,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Enumeration; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; @@ -152,7 +152,9 @@ public class JSONObject { * Construct an empty JSONObject. */ public JSONObject() { - this.map = new HashMap<String, Object>(); +// this.map = new HashMap<String, Object>(); + // I want to keep order of the given data: + this.map = new LinkedHashMap<String, Object>(); } /** @@ -243,7 +245,7 @@ public class JSONObject { * @throws JSONException */ public JSONObject(Map<String, Object> map) { - this.map = new HashMap<String, Object>(); + this.map = new LinkedHashMap<String, Object>(); if (map != null) { Iterator<Entry<String, Object>> i = map.entrySet().iterator(); while (i.hasNext()) {
quelle
Sie können den folgenden Code verwenden, um eine benutzerdefinierte ORDERED-Serialisierung und -Deserialisierung des JSON-Arrays durchzuführen (in diesem Beispiel wird davon ausgegangen, dass Sie Strings bestellen, diese können jedoch auf alle Typen angewendet werden):
Serialisierung
JSONArray params = new JSONArray(); int paramIndex = 0; for (String currParam : mParams) { JSONObject paramObject = new JSONObject(); paramObject.put("index", paramIndex); paramObject.put("value", currParam); params.put(paramObject); ++paramIndex; } json.put("orderedArray", params);
Deserialisierung
JSONArray paramsJsonArray = json.optJSONArray("orderedArray"); if (null != paramsJsonArray) { ArrayList<String> paramsArr = new ArrayList<>(); for (int i = 0; i < paramsJsonArray.length(); i++) { JSONObject param = paramsJsonArray.optJSONObject(i); if (null != param) { int paramIndex = param.optInt("index", -1); String paramValue = param.optString("value", null); if (paramIndex > -1 && null != paramValue) { paramsArr.add(paramIndex, paramValue); } } } }
quelle
Ihr Beispiel:
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ... ] }
füge ein Element "itemorder" hinzu
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ... ], "itemorder":["WR","QU","QA","WO","NO"] }
Dieser Code generiert die gewünschte Ausgabe ohne die Spalte Titelzeile:
JSONObject output = new JSONObject(json); JSONArray docs = output.getJSONArray("data"); JSONArray names = output.getJSONArray("itemOrder"); String csv = CDL.toString(names,docs);
quelle
Anstatt jsonObject zu verwenden, versuchen Sie es mit CsvSchema einfacher und konvertieren Sie Objekte direkt in CSV
und es mentains den Auftrag ID Ihre pojo hat @JsonPropertyOrder drin
quelle
Underscore-java behält beim Lesen von json die Reihenfolge der Elemente bei. Ich bin der Betreuer des Projekts.
String json = "{\n" + " \"items\":\n" + " [\n" + " {\n" + " \"WR\":\"qwe\",\n" + " \"QU\":\"asd\",\n" + " \"QA\":\"end\",\n" + " \"WO\":\"hasd\",\n" + " \"NO\":\"qwer\"\n" + " }\n" + " ]\n" + "}"; System.out.println(U.fromJson(json)); // {items=[{WR=qwe, QU=asd, QA=end, WO=hasd, NO=qwer}]}
quelle
Getestet die Wink-Lösung und funktioniert gut:
@Test public void testJSONObject() { JSONObject jsonObject = new JSONObject(); jsonObject.put("bbb", "xxx"); jsonObject.put("ccc", "xxx"); jsonObject.put("aaa", "xxx"); jsonObject.put("xxx", "xxx"); System.out.println(jsonObject.toString()); assertTrue(jsonObject.toString().startsWith("{\"xxx\":")); } @Test public void testWinkJSONObject() throws JSONException { org.apache.wink.json4j.JSONObject jsonObject = new OrderedJSONObject(); jsonObject.put("bbb", "xxx"); jsonObject.put("ccc", "xxx"); jsonObject.put("aaa", "xxx"); jsonObject.put("xxx", "xxx"); assertEquals("{\"bbb\":\"xxx\",\"ccc\":\"xxx\",\"aaa\":\"xxx\",\"xxx\":\"xxx\"}", jsonObject.toString()); }
quelle