Gson hat ein merkwürdiges Verhalten, wenn ich versuche, einen String in json zu konvertieren. Der folgende Code wandelt den Zeichenfolgenentwurf in JSON-Antworten um. Gibt es eine Möglichkeit zu verhindern, dass gson allen ganzzahligen Werten die '.0 hinzufügt?
ArrayList<Hashtable<String, Object>> responses;
Type ResponseList = new TypeToken<ArrayList<Hashtable<String, Object>>>() {}.getType();
responses = new Gson().fromJson(draft, ResponseList);
draft:
[ {"id":4077395,"field_id":242566,"body":""},
{"id":4077398,"field_id":242569,"body":[[273019,0],[273020,1],[273021,0]]},
{"id":4077399,"field_id":242570,"body":[[273022,0],[273023,1],[273024,0]]}
]
responses:
[ {id=4077395.0, body=, field_id=242566.0},
{id=4077398.0, body=[[273019.0, 0.0], [273020.0, 1.0], [273021.0, 0.0]], field_id=242569.0},
{id=4077399.0, body=[[273022.0, 0.0], [273023.0, 1.0], [273024.0, 0.0]], field_id=242570.0}
]
Object
und dann auf das übertragen müssen, was Sie benötigen.Antworten:
Sie sagen Gson, dass es nach einer Liste von Karten von Strings zu Objekten sucht, die im Wesentlichen besagt, dass es eine bestmögliche Vermutung über den Typ des Objekts gibt. Da JSON nicht zwischen Ganzzahl- und Gleitkommafeldern unterscheidet, muss Gson für numerische Felder standardmäßig Gleitkomma / Double verwenden.
Gson wurde im Wesentlichen entwickelt, um den Typ des Objekts zu untersuchen, das Sie füllen möchten, um festzustellen, wie die Daten analysiert werden. Wenn Sie keinen Hinweis geben, wird es nicht sehr gut funktionieren. Eine Möglichkeit besteht darin, einen benutzerdefinierten JsonDeserializer zu definieren. Besser wäre es jedoch, keine HashMap zu verwenden (und definitiv keine Hashtable zu verwenden!) Und stattdessen Gson mehr Informationen über den erwarteten Datentyp zu geben.
class Response { int id; int field_id; ArrayList<ArrayList<Integer>> body; // or whatever type is most apropriate } responses = new Gson() .fromJson(draft, new TypeToken<ArrayList<Response>>(){}.getType());
Auch hier geht es bei Gson darum, strukturierte Daten nahtlos in strukturierte Objekte umzuwandeln. Wenn Sie darum bitten, eine nahezu undefinierte Struktur wie eine Liste von Objektkarten zu erstellen, besiegen Sie den gesamten Punkt von Gson und können auch einen einfacheren JSON-Parser verwenden.
quelle
TaggedValue
Typ mit dem WertDas funktioniert:
Gson gson = new GsonBuilder(). registerTypeAdapter(Double.class, new JsonSerializer<Double>() { @Override public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { if(src == src.longValue()) return new JsonPrimitive(src.longValue()); return new JsonPrimitive(src); } }).create();
quelle
Grundsätzlich gibt es keine perfekte Antwort auf dieses Problem. Alle "Lösungen" funktionieren nur in einigen Fällen. Dies ist ein Problem, das dem gson-Team gemeldet wurde. Leider scheinen sie darauf zu bestehen, dass "Javascript keinen ganzzahligen Typ hat", als ob sie nicht erkennen, dass gson für Java und nicht für Javascript ist. Deshalb haben sie sich bis heute (jetzt 2018) geweigert, das Problem zu beheben, obwohl andere Bibliotheken wie Jackson überhaupt kein solches Problem haben, obwohl es so einfach zu beheben ist. Daher müssen Sie das Problem möglicherweise selbst aus dem gson-Quellcode beheben und Ihre eigene gson.jar erstellen. Die Quelldatei ist
gson/src/main/java/com/google/gson/internal/bind/ObjectTypeAdapter.java
case NUMBER: return in.nextDouble();
quelle
Ich bin zu spät zur Party, aber ich bin selbst darauf gestoßen. In meinem Fall wollte ich in meiner ArrayList keinen Integer-Typ angeben, da es sich um einen String oder eine Integer handeln kann.
Meine Lösung lautet wie folgt:
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Double.class, new JsonSerializer<Double>() { public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { Integer value = (int)Math.round(src); return new JsonPrimitive(value); } }); Gson gs = gsonBuilder.create();
Anstatt die Standard-Gson-Definition mit zu verwenden
Gson gs = new Gson();
, habe ich die Double.class-Serialisierung überschrieben, um eine Ganzzahl zurückzugeben.In meinem Fall habe ich Strings und Integers in meinem JSON, aber ich habe keine Doubles, so dass dies kein Problem darstellt.
Wenn Sie einen doppelten oder einen Gleitkommawert benötigen, ist es wahrscheinlich möglich, eine Logik hinzuzufügen, die den Wert auf Attribute testet, die für jeden Datentyp spezifisch sind, und einen geeigneten Wert zurückgibt. Etwas wie
if(/*source has a decimal point*/){ return new JsonPrimitive(src); } else if (/* source has some attribute of a Float */){ Float value = /*convert the src value from double to a Float */; return new JsonPrimitive(value); } else { //it looks like an integer Integer value = (int)Math.round(src); return new JsonPrimitive(value); }
Ich weiß nicht, wie ich diese Datentypen testen oder konvertieren soll, aber das sollte Sie auf den richtigen Weg bringen.
quelle
Diese Arbeit für mich.
Schritt 1: Kopieren Sie den ObjectTypeAdapter in gson in das Projekt, und behalten Sie dabei den Pfad wie in gson bei
Schritt 2: Ändern Sie ObjectTypeAdapter
case NUMBER: return in.nextDouble();
Geändert zu
case NUMBER: String number = in.nextString(); try { return Long.valueOf(number); } catch (NumberFormatException e) { return Double.valueOf(number); }
IN ORDNUNG. Gson priorisiert den ObjectTypeAdapter im Projekt.
quelle
fun jsonToMap(json: JSONObject): Map<String, Any> { val doubles = Gson().fromJson<Map<String, Any>>(json.toString(), Map::class.java) fun doublesToLong(doubles: Map<String, Any>): Map<String, Any> = doubles .map { entry -> Pair(entry.key, entry.value.let { when (it) { is Map<*, *> -> doublesToLong(it as Map<String, Any>) is Double -> it.toLong() else -> it } }) } .toMap() return doublesToLong(doubles) }
quelle