Zoeken…


Invoering

Gson is een Java-bibliotheek die kan worden gebruikt om Java-objecten om te zetten in hun JSON-weergave. Gson beschouwt deze beide als zeer belangrijke ontwerpdoelen.

Gson-kenmerken:

Lever eenvoudige toJson() en fromJson() methoden om Java-objecten naar JSON te converteren en vice versa

Sta toe dat reeds bestaande niet-wijzigbare objecten naar en van JSON worden geconverteerd

Uitgebreide ondersteuning van Java Generics

Ondersteuning van willekeurig complexe objecten (met diepe overervinghiërarchieën en uitgebreid gebruik van generieke typen)

Syntaxis

  • Excluder excluder ()
  • FieldNamingStrategy fieldNamingStrategy ()
  • <T> T fromJson (JsonElement json, Class <T> classOfT)
  • <T> T fromJson (JsonElement json, Type typeOfT)
  • <T> T fromJson (JsonReader reader, Type typeOfT)
  • <T> T fromJson (Reader json, Class <T> classOfT)
  • <T> T fromJson (Reader json, Type typeOfT)
  • <T> T fromJson (String json, Class <T> classOfT)
  • <T> T fromJson (String json, Type typeOfT)
  • <T> TypeAdapter <T> getAdapter (Klasse <T> type)
  • <T> TypeAdapter <T> getAdapter (TypeToken <T> type)
  • <T> TypeAdapter <T> getDelegateAdapter (TypeAdapterFactory skipPast, TypeToken <T> type)
  • JsonReader nieuwJsonReader (Reader reader)
  • JsonWriter newJsonWriter (Writer writer)
  • JsonElement toJsonTree (Object src)
  • JsonElement toJsonTree (Object src, Type typeOfSrc)
  • boolean serializeNulls ()
  • boolean htmlSafe ()
  • String toJson (JsonElement jsonElement)
  • String toJson (Object src)
  • String toJson (Object src, Type typeOfSrc)
  • String toString ()
  • void toJson (Object src, Type typeOfSrc, Appendable writer)
  • void toJson (Object src, Type typeOfSrc, JsonWriter writer)
  • void toJson (JsonElement jsonElement, Appendable writer)
  • void toJson (JsonElement jsonElement, JsonWriter writer)
  • void toJson (Object src, Appendable writer)

JSON parseren met Gson

Het voorbeeld toont het parseren van een JSON-object met behulp van de Gson-bibliotheek van Google .

Objecten parseren:

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 = "";
    }


}

Gebruik vervolgens het volgende wanneer parseren moet plaatsvinden:

String robotJson = "{
                        \"version\": \"JellyBean\",
                        \"age\": 3,
                        \"robotName\": \"Droid\"
                   }";

Gson gson = new Gson();
Robot robot = gson.fromJson(robotJson, Robot.class);

Een lijst parseren:

Wanneer u een lijst met JSON-objecten ophaalt, wilt u deze vaak parseren en converteren naar Java-objecten.

De JSON-string die we zullen proberen te converteren is de volgende:

{
  "owned_dogs": [
    {
      "name": "Ron",
      "age": 12,
      "breed": "terrier"
    },
    {
      "name": "Bob",
      "age": 4,
      "breed": "bulldog"
    },
    {
      "name": "Johny",
      "age": 3,
      "breed": "golden retriever"
    }
  ]
}

Deze specifieke JSON-array bevat drie objecten. In onze Java-code willen we deze objecten toewijzen aan Dog objecten. Een object Dog ziet er zo uit:

private class Dog {
    public String name;
    public int age;

    @SerializedName("breed")
    public String breedName;
}

Om de JSON-array te converteren naar een Dog[] :

Dog[] arrayOfDogs = gson.fromJson(jsonArrayString, Dog[].class);

Een Dog[] converteren naar een JSON-reeks:

String jsonArray = gson.toJson(arrayOfDogs, Dog[].class);

Om de JSON-array te converteren naar een ArrayList<Dog> kunnen we het volgende doen:

Type typeListOfDogs = new TypeToken<List<Dog>>(){}.getType();
List<Dog> listOfDogs = gson.fromJson(jsonArrayString, typeListOfDogs);

Het Type object typeListOfDogs definieert hoe een lijst met Dog objecten eruit zou zien. GSON kan dit type object gebruiken om de JSON-array aan de juiste waarden toe te wijzen.

Als alternatief kan een List<Dog> naar een JSON-array worden omgezet op een vergelijkbare manier.

String jsonArray = gson.toJson(listOfDogs, typeListOfDogs);

JSON-eigenschap parseren voor Gson

Als je een string wilt parsen om met Gson op te tellen:

{"status": "open"}

public enum Status {
    @SerializedName("open")
    OPEN,
    @SerializedName("waiting")
    WAITING,
    @SerializedName("confirm")
    CONFIRM,
    @SerializedName("ready")
    READY
}

Een lijst parseren met 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());

Dit is handig voor de meeste generieke containerklassen, omdat u de klasse van een geparametriseerd type niet kunt List<String>.class (dat wil zeggen: u kunt List<String>.class niet aanroepen).

Methode 2

public class StringList extends ArrayList<String> { }

...

List<String> members = gson.fromJson(json, StringList.class);

Als alternatief kunt u altijd het gewenste type subklasse maken en vervolgens die klasse doorgeven. Dit is echter niet altijd de beste StringList , omdat het een object van het type StringList zal retourneren;

JSON Serialisatie / Deserialisatie met AutoValue en Gson

Importeer in je gradle rootbestand

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

Importeer in uw gradle-app-bestand

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'

Maak een object met autovalue:

@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);
    }
}

Maak uw Gson-omzetter met uw GsonBuilder

Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(
                    new AutoValueGsonTypeAdapterFactory())
                .create());

deserialize

String myJsonData = "{
    \"signin_token\": \"mySigninToken\",
    \"username\": \"myUsername\" }";
SignIn signInData = gson.fromJson(myJsonData, Signin.class);

serialize

Signin myData = SignIn.create("myTokenData", "myUsername");
String myJsonData = gson.toJson(myData);

Het gebruik van Gson is een geweldige manier om de code voor serialisatie en deserialisatie te vereenvoudigen met behulp van POJO-objecten. Het neveneffect is dat reflectie qua prestaties kostbaar is. Dat is de reden waarom het gebruik van AutoValue-Gson om CustomTypeAdapter te genereren, deze reflectiekosten voorkomt en zeer eenvoudig te updaten blijft wanneer er een API-verandering plaatsvindt.

JSON parseren naar Generic Class Object met Gson

Stel dat we een JSON-string hebben :

["first","second","third"]

We kunnen deze JSON-string ontleden in een String array:

Gson gson = new Gson();
String jsonArray = "[\"first\",\"second\",\"third\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);

Maar als we het in een List<String> -object willen parseren, moeten we TypeToken .

Hier is het voorbeeld:

Gson gson = new Gson();
String jsonArray = "[\"first\",\"second\",\"third\"]";
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());

Stel dat we hieronder twee klassen hebben:

public class Outer<T> {
    public int index;
    public T data;
}

public class Person {
    public String firstName;
    public String lastName;
}

en we hebben een JSON-string die moet worden geparseerd naar een Outer<Person> -object.

Dit voorbeeld laat zien hoe u deze JSON-reeks kunt parseren naar het gerelateerde generieke klasseobject:

String json = "......";
Type userType = new TypeToken<Outer<Person>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);

Als de JSON-string moet worden geparseerd naar een Outer<List<Person>> -object:

Type userListType = new TypeToken<Outer<List<Person>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType); 

Gson toevoegen aan uw project

dependencies {
    compile 'com.google.code.gson:gson:2.8.1'
}

Om de nieuwste versie van Gson te gebruiken

De onderstaande regel compileert de nieuwste versie van gson library telkens wanneer u compileert, u hoeft de versie niet te wijzigen.

Voordelen: u kunt de nieuwste functies, snelheid en minder bugs gebruiken.
Nadelen: het kan de compatibiliteit met uw code verbreken.

compile 'com.google.code.gson:gson:+'

Gson gebruiken om een JSON-bestand van schijf te laden.

Dit laadt een JSON-bestand van schijf en converteert het naar het gegeven type.

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);
}

Een aangepaste converter toevoegen aan Gson

Soms moet u sommige velden in een gewenst formaat serialiseren of deserialiseren, bijvoorbeeld uw backend kan het formaat "JJJJ-MM-dd HH: mm" gebruiken voor datums en u wilt dat uw POJOS de DateTime-klasse in Joda Time gebruikt.

Om deze strings automatisch te converteren naar DateTimes-object, kunt u een aangepaste converter gebruiken.

/**
 * 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());
    }
}

Om Gson de nieuw gemaakte converter te laten gebruiken, moet u deze toewijzen bij het maken van het Gson-object:

    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

Om de datum in dat formaat te deserialiseren, hoeft u alleen een veld in het DateTime-formaat te definiëren:

public class SomePojo {
    private DateTime someDate;    
} 

Wanneer Gson een veld van het type DateTime tegenkomt, zal het uw converter aanroepen om het veld te deserialiseren.

Gson gebruiken als serializer met Retrofit

Allereerst moet u de GsonConverterFactory aan uw build.gradle-bestand

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Vervolgens moet u de converterfabriek toevoegen bij het maken van de Retrofit-service:

Gson gson = new GsonBuilder().create();
new Retrofit.Builder()
        .baseUrl(someUrl)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
        .create(RetrofitService.class);

U kunt aangepaste converters toevoegen wanneer u het Gson-object maakt dat u doorgeeft aan de fabriek. Hiermee kunt u aangepaste type conversies maken.

Json-array met Gson naar generieke klasse parseren

Stel dat we een json hebben :

{
  "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"
    }
  ]
}

We kunnen deze array handmatig in een Custom Tweets (tweets list container) parseren, maar het is gemakkelijker om het te doen met de fromJson methode:

Gson gson = new Gson();
String jsonArray = "....";
Tweets tweets = gson.fromJson(jsonArray, Tweets.class);

Stel dat we hieronder twee klassen hebben:

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;
}

en als je gewoon een json-array moet parseren, kun je deze code gebruiken bij het parseren:

String tweetsJsonArray = "[{.....},{.....}]"
List<Tweet> tweets = gson.fromJson(tweetsJsonArray, new TypeToken<List<Tweet>>() {}.getType());

Aangepaste JSON Deserializer met behulp van Gson

Stel dat u alle datums in alle antwoorden in een aangepast formaat hebt, bijvoorbeeld /Date(1465935152)/ en dat u een algemene regel wilt toepassen om alle Json-datums te deserialiseren naar java Date instanties. In dit geval moet u aangepaste Json Deserializer implementeren.

Voorbeeld van json:

{
  "id": 1,
  "created_on": "Date(1465935152)",
  "updated_on": "Date(1465968945)",
  "name": "Oleksandr"
}

Stel dat we deze klasse hieronder hebben:

class User {
    @SerializedName("id")
    long id;
    @SerializedName("created_on")
    Date createdOn;
    @SerializedName("updated_on")
    Date updatedOn;
    @SerializedName("name")
    String name;
}

Aangepaste deserializer:

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());
    }
}

En het gebruik:

Gson gson = new GsonBuilder()
                .registerTypeAdapter(Date.class, new DateDeSerializer())
                .create();
String json = "....";
User user = gson.fromJson(json, User.class);

Serialiseer en deserialiseer Jackson JSON-strings met datumtypen

Dit geldt ook voor het geval waarin u Gson Date-conversie bijvoorbeeld compatibel wilt maken met Jackson.

Jackson rangschikt datum meestal in "milliseconden sinds het tijdperk", terwijl Gson een leesbaar formaat zoals Aug 31, 2016 10:26:17 om Datum te vertegenwoordigen. Dit leidt tot JsonSyntaxExceptions in Gson wanneer u probeert een Jackson-formaat Datum te deserialiseren.

Om dit te omzeilen, kunt u een aangepaste serializer en een aangepaste deserializer toevoegen:

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();

Gson gebruiken met overerving

Gson ondersteunt out-of-the-box geen erfenis.

Laten we zeggen dat we de volgende klassenhiërarchie hebben:

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;
    }
}

En nu willen we een exemplaar van DerivedClass1 naar een JSON-string

DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
 
Gson gson = new Gson();
String derivedClass1Json = gson.toJson(derivedClass1);

Nu, op een andere plaats, ontvangen we deze json-string en willen we deze deserialiseren - maar tijdens het compileren weten we alleen dat het een instantie van BaseClass :

BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());

Maar GSON weet niet dat derivedClass1Json oorspronkelijk een instantie was van DerivedClass1 , dus dit zal 10 afdrukken.

Hoe dit op te lossen?

U moet uw eigen JsonDeserializer bouwen, die dergelijke gevallen afhandelt. De oplossing is niet perfect schoon, maar ik kon geen betere bedenken.

Voeg eerst het volgende veld toe aan uw basisklasse

@SerializedName("type")
private String typeName;

En initialiseer het in de constructeur van de basisklasse

public BaseClass() {
    typeName = getClass().getName();
}

Voeg nu de volgende klasse toe:

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);
 }
}

U hoeft alleen nog maar alles aan te sluiten -

GsonBuilder builder = new GsonBuilder();
 builder
 .registerTypeAdapter(BaseClass.class, new JsonDeserializerWithInheritance<BaseClass>());
 Gson gson = builder.create();

En nu, met de volgende code-

 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());

Wordt afgedrukt 5.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow