Android
Gson
Suche…
Einführung
Gson ist eine Java-Bibliothek, mit der Java-Objekte in ihre JSON-Darstellung konvertiert werden können. Gson betrachtet beide als sehr wichtige Designziele.
Gson-Eigenschaften:
Stellen Sie einfache toJson()
und fromJson()
Methoden fromJson()
, um Java-Objekte in JSON und umgekehrt zu konvertieren
Zulassen, dass vorhandene, nicht veränderbare Objekte in und aus JSON konvertiert werden
Umfassende Unterstützung von Java Generics
Unterstützung beliebig komplexer Objekte (mit tiefen Vererbungshierarchien und umfangreicher Verwendung generischer Typen)
Syntax
- Ausschluss-Ausschluss ()
- FieldNamingStrategy fieldNamingStrategy ()
- <T> T von Json (JsonElement Json, Klasse <T> classOfT)
- <T> T von Json (JsonElement Json, Type TypeOfT)
- <T> T fromJson (JsonReader-Leser, Typ typeOfT)
- <T> T von Json (Reader Json, Class <T> classOfT)
- <T> T von Json (Reader Json, Type TypeOfT)
- <T> T fromJson (String json, Klasse <T> classOfT)
- <T> T fromJson (String json, Type typeOfT)
- <T> TypeAdapter <T> getAdapter (Klasse <T> -Typ)
- <T> TypeAdapter <T> getAdapter (TypeToken <T> -Typ)
- <T> TypeAdapter <T> getDelegateAdapter (TypeAdapterFactory skipPast, TypeToken <T> -Typ)
- JsonReader newJsonReader (Leser)
- JsonWriter newJsonWriter (Writer Writer)
- JsonElement toJsonTree (Object src)
- JsonElement toJsonTree (Object src, Typ typeOfSrc)
- boolean serializeNulls ()
- boolean htmlSafe ()
- Zeichenfolge toJson (JsonElement JsonElement)
- Zeichenfolge toJson (Object src)
- Zeichenfolge toJson (Object src, Type typeOfSrc)
- String toString ()
- void toJson (Object src, Type typeOfSrc, Appendable Writer)
- void toJson (Object src, Type typeOfSrc, JsonWriter-Schreiber)
- toJson ungültig (JsonElement JsonElement, Appendable Writer)
- toJson ungültig (JsonElement JsonElement, JsonWriter Writer)
- void toJson (Object src, Anhängbarer Schreiber)
Parsen von JSON mit Gson
Das Beispiel zeigt die Analyse eines JSON-Objekts mit der Gson-Bibliothek von Google .
Objekte analysieren:
class Robot {
//OPTIONAL - this annotation allows for the key to be different from the field name, and can be omitted if key and field name are same . Also this is good coding practice as it decouple your variable names with server keys name
@SerializedName("version")
private String version;
@SerializedName("age")
private int age;
@SerializedName("robotName")
private String name;
// optional : Benefit it allows to set default values and retain them, even if key is missing from Json response. Not required for primitive data types.
public Robot{
version = "";
name = "";
}
}
Verwenden Sie dann, wo eine Analyse erfolgen muss, Folgendes:
String robotJson = "{
\"version\": \"JellyBean\",
\"age\": 3,
\"robotName\": \"Droid\"
}";
Gson gson = new Gson();
Robot robot = gson.fromJson(robotJson, Robot.class);
Eine Liste analysieren:
Wenn Sie eine Liste von JSON-Objekten abrufen, möchten Sie sie häufig analysieren und in Java-Objekte konvertieren.
Die JSON-Zeichenfolge, die wir zu konvertieren versuchen, lautet wie folgt:
{
"owned_dogs": [
{
"name": "Ron",
"age": 12,
"breed": "terrier"
},
{
"name": "Bob",
"age": 4,
"breed": "bulldog"
},
{
"name": "Johny",
"age": 3,
"breed": "golden retriever"
}
]
}
Dieses spezielle JSON-Array enthält drei Objekte. In unserem Java-Code möchten wir diese Objekte Dog
Objekten Dog
. Ein Dog-Objekt würde folgendermaßen aussehen:
private class Dog {
public String name;
public int age;
@SerializedName("breed")
public String breedName;
}
So konvertieren Sie das JSON-Array in einen Dog[]
:
Dog[] arrayOfDogs = gson.fromJson(jsonArrayString, Dog[].class);
Konvertieren eines Dog[]
in einen JSON-String:
String jsonArray = gson.toJson(arrayOfDogs, Dog[].class);
Um das JSON-Array in eine ArrayList<Dog>
zu konvertieren, können Sie Folgendes tun:
Type typeListOfDogs = new TypeToken<List<Dog>>(){}.getType();
List<Dog> listOfDogs = gson.fromJson(jsonArrayString, typeListOfDogs);
Das Type-Objekt typeListOfDogs
definiert, wie eine Liste von Dog
Objekten aussehen würde. GSON kann dieses Typobjekt verwenden, um das JSON-Array den richtigen Werten zuzuordnen.
Alternativ kann das Konvertieren einer List<Dog>
in ein JSON-Array auf ähnliche Weise erfolgen.
String jsonArray = gson.toJson(listOfDogs, typeListOfDogs);
Analysieren der JSON-Eigenschaft mit Gson
Wenn Sie einen String für die Enumeration mit Gson analysieren möchten:
{"status": "open"}
public enum Status {
@SerializedName("open")
OPEN,
@SerializedName("waiting")
WAITING,
@SerializedName("confirm")
CONFIRM,
@SerializedName("ready")
READY
}
Eine Liste analysieren mit Gson
Methode 1
Gson gson = new Gson();
String json = "[ \"Adam\", \"John\", \"Mary\" ]";
Type type = new TypeToken<List<String>>(){}.getType();
List<String> members = gson.fromJson(json, type);
Log.v("Members", members.toString());
Dies ist für die meisten generischen Containerklassen hilfreich, da Sie die Klasse eines parametrisierten Typs nicht abrufen können (z. B. List<String>.class
).
Methode 2
public class StringList extends ArrayList<String> { }
...
List<String> members = gson.fromJson(json, StringList.class);
Alternativ können Sie den gewünschten Typ immer einer Unterklasse zuordnen und diese Klasse dann übergeben. Dies ist jedoch nicht immer die bewährte StringList
, da ein Objekt vom Typ StringList
an Sie StringList
.
JSON-Serialisierung / Deserialisierung mit AutoValue und Gson
Importieren Sie in Ihrer Gradle-Root-Datei
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
Importieren Sie Ihre Gradle-App-Datei
apt 'com.google.auto.value:auto-value:1.2'
apt 'com.ryanharter.auto.value:auto-value-gson:0.3.1'
provided 'com.jakewharton.auto.value:auto-value-annotations:1.2-update1'
provided 'org.glassfish:javax.annotation:10.0-b28'
Objekt mit automatischem Wert erstellen:
@AutoValue public abstract class SignIn {
@SerializedName("signin_token") public abstract String signinToken();
public abstract String username();
public static TypeAdapter<SignIn> typeAdapter(Gson gson) {
return new AutoValue_SignIn.GsonTypeAdapter(gson);
}
public static SignIn create(String signin, String username) {
return new AutoValue_SignIn(signin, username);
}
}
Erstellen Sie Ihren Gson-Konverter mit Ihrem GsonBuilder
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(
new AutoValueGsonTypeAdapterFactory())
.create());
Deserialisieren
String myJsonData = "{
\"signin_token\": \"mySigninToken\",
\"username\": \"myUsername\" }";
SignIn signInData = gson.fromJson(myJsonData, Signin.class);
Serialisieren
Signin myData = SignIn.create("myTokenData", "myUsername");
String myJsonData = gson.toJson(myData);
Die Verwendung von Gson ist eine großartige Möglichkeit, den Serialisierungs- und Deserialisierungscode mithilfe von POJO-Objekten zu vereinfachen. Der Nebeneffekt ist, dass die Reflexion kostspielig ist. Durch die Verwendung von AutoValue-Gson zur Generierung von CustomTypeAdapter werden diese Reflexionskosten vermieden und es bleibt sehr einfach zu aktualisieren, wenn eine API-Änderung stattfindet.
Parsen von JSON in generische Klassenobjekte mit Gson
Angenommen, wir haben eine JSON-Zeichenfolge:
["first","second","third"]
Wir können diesen JSON-String in ein String
Array parsen:
Gson gson = new Gson();
String jsonArray = "[\"first\",\"second\",\"third\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
Wenn wir es jedoch in ein List<String>
-Objekt analysieren wollen, müssen wir TypeToken
.
Hier ist die Probe:
Gson gson = new Gson();
String jsonArray = "[\"first\",\"second\",\"third\"]";
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());
Nehmen wir an, wir haben zwei Klassen:
public class Outer<T> {
public int index;
public T data;
}
public class Person {
public String firstName;
public String lastName;
}
und wir haben eine JSON-Zeichenfolge, die in ein Outer<Person>
-Objekt analysiert werden sollte.
In diesem Beispiel wird veranschaulicht, wie diese JSON-Zeichenfolge in das verwandte generische Klassenobjekt analysiert wird:
String json = "......";
Type userType = new TypeToken<Outer<Person>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);
Wenn die JSON-Zeichenfolge in ein Outer<List<Person>>
-Objekt analysiert werden soll:
Type userListType = new TypeToken<Outer<List<Person>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType);
Hinzufügen von Gson zu Ihrem Projekt
dependencies {
compile 'com.google.code.gson:gson:2.8.1'
}
Um die neueste Version von Gson zu verwenden
Die folgende Zeile wird die neueste Version der Gson-Bibliothek bei jedem Kompilieren kompilieren.
Vorteile: Sie können die neuesten Funktionen, die Geschwindigkeit und weniger Fehler verwenden.
Nachteile: Es könnte die Kompatibilität mit Ihrem Code beeinträchtigen.
compile 'com.google.code.gson:gson:+'
Gson verwenden, um eine JSON-Datei von der Festplatte zu laden.
Dadurch wird eine JSON-Datei von der Festplatte geladen und in den angegebenen Typ konvertiert.
public static <T> T getFile(String fileName, Class<T> type) throws FileNotFoundException {
Gson gson = new GsonBuilder()
.create();
FileReader json = new FileReader(fileName);
return gson.fromJson(json, type);
}
Hinzufügen eines benutzerdefinierten Konverters zu Gson
Manchmal müssen Sie einige Felder in einem gewünschten Format serialisieren oder deserialisieren. Beispielsweise verwendet Ihr Backend das Format "JJJJ-MM-tt HH: mm" für Datumsangaben und Sie möchten, dass Ihr POJOS die DateTime-Klasse in Joda Time verwendet.
Um diese Zeichenfolgen automatisch in ein DateTimes-Objekt zu konvertieren, können Sie einen benutzerdefinierten Konverter verwenden.
/**
* Gson serialiser/deserialiser for converting Joda {@link DateTime} objects.
*/
public class DateTimeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
private final DateTimeFormatter dateTimeFormatter;
@Inject
public DateTimeConverter() {
this.dateTimeFormatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm");
}
@Override
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(dateTimeFormatter.print(src));
}
@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (json.getAsString() == null || json.getAsString().isEmpty()) {
return null;
}
return dateTimeFormatter.parseDateTime(json.getAsString());
}
}
Damit Gson den neu erstellten Konverter verwenden kann, müssen Sie ihn beim Erstellen des Gson-Objekts zuweisen:
DateTimeConverter dateTimeConverter = new DateTimeConverter();
Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, dateTimeConverter)
.create();
String s = gson.toJson(DateTime.now());
// this will show the date in the desired format
Um das Datum in diesem Format zu deserialisieren, müssen Sie lediglich ein Feld im DateTime-Format definieren:
public class SomePojo {
private DateTime someDate;
}
Wenn Gson auf ein Feld des Typs DateTime trifft, ruft es Ihren Konverter auf, um das Feld zu deserialisieren.
Verwendung von Gson als Serializer mit Retrofit
Zunächst müssen Sie die GsonConverterFactory
zu Ihrer build.gradle-Datei hinzufügen
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
Dann müssen Sie die Konverter-Factory hinzufügen, wenn Sie den Retrofit-Service erstellen:
Gson gson = new GsonBuilder().create();
new Retrofit.Builder()
.baseUrl(someUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(RetrofitService.class);
Sie können benutzerdefinierte Konverter hinzufügen, wenn Sie das Gson-Objekt erstellen, das Sie an die Factory übergeben. So können Sie benutzerdefinierte Typkonvertierungen erstellen.
Json-Array wird mit Gson in eine generische Klasse geparst
Angenommen, wir haben einen Json :
{
"total_count": 132,
"page_size": 2,
"page_index": 1,
"twitter_posts": [
{
"created_on": 1465935152,
"tweet_id": 210462857140252672,
"tweet": "Along with our new #Twitterbird, we've also updated our Display Guidelines",
"url": "https://twitter.com/twitterapi/status/210462857140252672"
},
{
"created_on": 1465995741,
"tweet_id": 735128881808691200,
"tweet": "Information on the upcoming changes to Tweets is now on the developer site",
"url": "https://twitter.com/twitterapi/status/735128881808691200"
}
]
}
Wir können dieses Array manuell in ein Objekt für benutzerdefinierte Tweets (Tweets- fromJson
) parsen, es ist jedoch einfacher, die fromJson
Methode zu verwenden:
Gson gson = new Gson();
String jsonArray = "....";
Tweets tweets = gson.fromJson(jsonArray, Tweets.class);
Nehmen wir an, wir haben zwei Klassen:
class Tweets {
@SerializedName("total_count")
int totalCount;
@SerializedName("page_size")
int pageSize;
@SerializedName("page_index")
int pageIndex;
// all you need to do it is just define List variable with correct name
@SerializedName("twitter_posts")
List<Tweet> tweets;
}
class Tweet {
@SerializedName("created_on")
long createdOn;
@SerializedName("tweet_id")
String tweetId;
@SerializedName("tweet")
String tweetBody;
@SerializedName("url")
String url;
}
und wenn Sie nur ein Json-Array analysieren müssen, können Sie diesen Code bei der Analyse verwenden:
String tweetsJsonArray = "[{.....},{.....}]"
List<Tweet> tweets = gson.fromJson(tweetsJsonArray, new TypeToken<List<Tweet>>() {}.getType());
Benutzerdefinierter JSON-Deserializer mit Gson
Stellen Sie sich vor, Sie haben alle Datumsangaben in allen Antworten in einem benutzerdefinierten Format, z. B. /Date(1465935152)/
und Sie möchten die Regel anwenden, um alle Json-Datumsangaben zu java Date
Instanzen zu deserialisieren. In diesem Fall müssen Sie einen benutzerdefinierten Json Deserializer implementieren.
Beispiel für Json:
{
"id": 1,
"created_on": "Date(1465935152)",
"updated_on": "Date(1465968945)",
"name": "Oleksandr"
}
Angenommen, wir haben diese Klasse unten:
class User {
@SerializedName("id")
long id;
@SerializedName("created_on")
Date createdOn;
@SerializedName("updated_on")
Date updatedOn;
@SerializedName("name")
String name;
}
Kundenspezifischer Deserialisierer:
class DateDeSerializer implements JsonDeserializer<Date> {
private static final String DATE_PREFIX = "/Date(";
private static final String DATE_SUFFIX = ")/";
@Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String dateString = json.getAsString();
if (dateString.startsWith(DATE_PREFIX) && dateString.endsWith(DATE_SUFFIX)) {
dateString = dateString.substring(DATE_PREFIX.length(), dateString.length() - DATE_SUFFIX.length());
} else {
throw new JsonParseException("Wrong date format: " + dateString);
}
return new Date(Long.parseLong(dateString) - TimeZone.getDefault().getRawOffset());
}
}
Und die Verwendung:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateDeSerializer())
.create();
String json = "....";
User user = gson.fromJson(json, User.class);
Serialisieren und deserialisieren Sie Jackson JSON-Zeichenfolgen mit Date-Typen
Dies gilt beispielsweise auch für den Fall, dass Sie die Konvertierung von Gson Date mit Jackson kompatibel machen möchten.
Jackson serialisiert Date normalerweise in "Millisekunden seit der Epoche", während Gson ein lesbares Format wie den Aug 31, 2016 10:26:17
, um Date darzustellen. Dies führt zu JsonSyntaxExceptions in Gson, wenn Sie versuchen, ein Datum im Jackson-Format zu deserialisieren.
Um dies zu umgehen, können Sie einen benutzerdefinierten Serializer und einen benutzerdefinierten Deserializer hinzufügen:
JsonSerializer<Date> ser = new JsonSerializer<Date>() {
@Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext
context) {
return src == null ? null : new JsonPrimitive(src.getTime());
}
};
JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return json == null ? null : new Date(json.getAsLong());
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, ser)
.registerTypeAdapter(Date.class, deser)
.create();
Verwendung von Gson mit Vererbung
Gson unterstützt nicht die sofortige Vererbung.
Nehmen wir an, wir haben die folgende Klassenhierarchie:
public class BaseClass {
int a;
public int getInt() {
return a;
}
}
public class DerivedClass1 extends BaseClass {
int b;
@Override
public int getInt() {
return b;
}
}
public class DerivedClass2 extends BaseClass {
int c;
@Override
public int getInt() {
return c;
}
}
Und jetzt möchten wir eine Instanz von DerivedClass1
in einen JSON-String serialisieren
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
Gson gson = new Gson();
String derivedClass1Json = gson.toJson(derivedClass1);
Nun, an einem anderen Ort, erhalten wir diesen Json-String und möchten ihn deserialisieren - aber zur Kompilierzeit wissen wir nur, dass es sich um eine Instanz von BaseClass
:
BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());
Aber GSON weiß nicht, dass derivedClass1Json
ursprünglich eine Instanz von DerivedClass1
, daher werden 10 DerivedClass1
.
Wie löse ich das?
Sie müssen einen eigenen JsonDeserializer
, der solche Fälle behandelt. Die Lösung ist nicht perfekt sauber, aber ich könnte mir keine bessere vorstellen.
Fügen Sie zunächst der Basisklasse das folgende Feld hinzu
@SerializedName("type")
private String typeName;
Und initialisieren Sie es im Basisklassenkonstruktor
public BaseClass() {
typeName = getClass().getName();
}
Fügen Sie nun folgende Klasse hinzu:
public class JsonDeserializerWithInheritance<T> implements JsonDeserializer<T> {
@Override
public T deserialize(
JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonPrimitive classNamePrimitive = (JsonPrimitive) jsonObject.get("type");
String className = classNamePrimitive.getAsString();
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
return context.deserialize(jsonObject, clazz);
}
}
Jetzt bleibt nur noch alles anzuschließen -
GsonBuilder builder = new GsonBuilder();
builder
.registerTypeAdapter(BaseClass.class, new JsonDeserializerWithInheritance<BaseClass>());
Gson gson = builder.create();
Und jetzt den folgenden Code ausführen:
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
String derivedClass1Json = gson.toJson(derivedClass1);
BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());
Wird ausgedruckt 5.