Sök…


Introduktion

Gson är ett Java-bibliotek som kan användas för att konvertera Java-objekt till deras JSON-representation. Gson betraktar båda dessa som mycket viktiga designmål.

Gson-funktioner:

Ge enkla toJson() och fromJson() metoder för att konvertera Java-objekt till JSON och vice versa

Tillåt att befintliga omodifierbara objekt konverteras till och från JSON

Omfattande stöd för Java Generics

Stödja godtyckligt komplexa objekt (med djupa arvshierarkier och omfattande användning av generiska typer)

Syntax

  • Excluder excluder ()
  • FieldNamingStrategy fieldNamingStrategy ()
  • <T> T fromJson (JsonElement json, Class <T> classOfT)
  • <T> T frånJson (JsonElement json, Type typeOfT)
  • <T> T frånJson (JsonReaderläsare, Type typeOfT)
  • <T> T frånJson (Reader json, Class <T> classOfT)
  • <T> T frånJson (Reader json, Type typeOfT)
  • <T> T fromJson (String json, Class <T> classOfT)
  • <T> T frånJson (String json, Type typeOfT)
  • <T> Type Adapter <T> get Adapter (typ <T>)
  • <T> Type Adapter <T> get Adapter (TypeToken <T> type)
  • <T> Type Adapter <T> getDelegate Adapter (Type AdapterFactory skipPast, TypeToken <T> type)
  • JsonReader newJsonReader (Readerläsare)
  • 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, tilläggsskribent)
  • void toJson (JsonElement jsonElement, JsonWriter författare)
  • void toJson (Object src, appendable Writer)

Analysera JSON med Gson

Exemplet visar att analysera ett JSON-objekt med Gson-biblioteket från Google .

Analysera objekt:

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


}

Använd sedan följande när parsning måste ske:

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

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

Analysera en lista:

När du hämtar en lista med JSON-objekt vill du ofta analysera dem och konvertera dem till Java-objekt.

JSON-strängen som vi kommer att försöka konvertera är följande:

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

Denna specifika JSON-grupp innehåller tre objekt. I vår Java-kod vill vi kartlägga dessa objekt till Dog objekt. Ett hundobjekt skulle se ut så här:

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

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

Så här konverterar du JSON-arrayen till en Dog[] :

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

Konvertera en Dog[] till en JSON-sträng:

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

För att konvertera JSON-arrayen till en ArrayList<Dog> vi göra följande:

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

typeListOfDogs definierar hur en lista med Dog skulle se ut. GSON kan använda detta typobjekt för att kartlägga JSON-arrayen till rätt värden.

Alternativt kan konvertering av en List<Dog> till en JSON-grupp göras på liknande sätt.

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

Analysera JSON-egendom till enum med Gson

Om du vill analysera en String to enum med Gson:

{"status": "open"}

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

Analysera en lista med Gson

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

Detta är användbart för de flesta generiska behållarklasser, eftersom du inte kan få klass av en parametrerad typ (dvs: du kan inte ringa List<String>.class ).

Metod 2

public class StringList extends ArrayList<String> { }

...

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

Alternativt kan du alltid underklassera den typ du vill ha och sedan skicka in den klassen. Men detta är inte alltid bästa praxis, eftersom det kommer att returnera ett objekt av typen StringList ;

JSON Serialisering / Deserialisering med AutoValue och Gson

Importera i din graderotfil

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

Importera i din gradle-appfil

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'

Skapa objekt med 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);
    }
}

Skapa din Gson-omvandlare med din GsonBuilder

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

avserialisera

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

Serialisera

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

Att använda Gson är ett bra sätt att förenkla serialisering och deserialiseringskod med hjälp av POJO-objekt. Biverkningen är att reflektion är kostsamt prestandamässigt. Det är därför som att använda AutoValue-Gson för att generera CustomTypeAdapter kommer att undvika denna reflektionskostnad medan du håller dig mycket enkel att uppdatera när en api-förändring sker.

Analysera JSON till Generic Class Object med Gson

Anta att vi har en JSON-sträng :

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

Vi kan tolka detta JSON sträng till en String array:

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

Men om vi vill analysera det till ett List<String> -objekt, måste vi använda TypeToken .

Här är exemplet:

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

Anta att vi har två klasser nedan:

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

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

och vi har en JSON-sträng som bör analyseras till ett Outer<Person> -objekt.

Det här exemplet visar hur man parar denna JSON-sträng till det relaterade generiska klassobjektet:

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

Om JSON-strängen ska tolkas till ett Outer<List<Person>> -objekt:

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

Lägga till Gson i ditt projekt

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

För att använda den senaste versionen av Gson

Nedanstående rad kommer att sammanställa den senaste versionen av gson-biblioteket varje gång du sammanställer, du behöver inte byta version.

Fördelar: Du kan använda de senaste funktionerna, hastigheten och mindre buggar.
Nackdelar: Det kan bryta kompatibiliteten med din kod.

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

Använda Gson för att ladda en JSON-fil från disken.

Detta laddar en JSON-fil från disken och konverterar den till den angivna typen.

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

Lägga till en anpassad omvandlare till Gson

Ibland måste du serialisera eller deserialisera vissa fält i önskat format, till exempel kan din backend använda formatet "YYYY-MM-dd HH: mm" för datum och du vill att dina POJOS ska använda klassen DateTime i Joda Time.

För att automatiskt konvertera dessa strängar till DateTimes-objekt kan du använda en anpassad omvandlare.

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

För att Gson ska använda den nyligen skapade omvandlaren måste du tilldela den när du skapar Gson-objektet:

    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

För att deserialisera datumet i det formatet behöver du bara definiera ett fält i DateTime-formatet:

public class SomePojo {
    private DateTime someDate;    
} 

När Gson möter ett fält av typen DateTime kommer den att ringa din omvandlare för att deserialisera fältet.

Med Gson som serienummer med Retrofit

Först måste du lägga till GsonConverterFactory i din build.gradle-fil

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

Sedan måste du lägga till konverteringsfabriken när du skapar ombyggnadstjänsten:

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

Du kan lägga till anpassade omvandlare när du skapar Gson-objektet som du skickar till fabriken. Tillåter dig att skapa konverteringar av anpassad typ.

Parsing json array till generisk klass med Gson

Anta att vi har en 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"
    }
  ]
}

Vi kan analysera denna grupp i ett anpassat tweets (behållare med fromJson ) manuellt, men det är lättare att göra det med fromJson metoden:

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

Anta att vi har två klasser nedan:

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

och om du bara behöver analysera en json-grupp kan du använda den här koden i din analys:

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

Anpassad JSON Deserializer med Gson

Tänk dig att du har alla datum i alla svar i vissa anpassade format, till exempel /Date(1465935152)/ och du vill tillämpa regel att avserialisera alla JSON datum till Java Date instanser. I detta fall måste du implementera anpassad Json Deserializer.

Exempel på json:

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

Anta att vi har den här klassen nedan:

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

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

Och användningen:

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

Serialisera och deserialisera Jackson JSON-strängar med datumtyper

Detta gäller också för fallet där du till exempel vill göra Gson Date-konvertering kompatibel med Jackson.

Jackson serialiserar vanligtvis Datum till "millisekunder sedan epok" medan Gson använder ett läsbart format som Aug 31, 2016 10:26:17 att representera Date. Detta leder till JsonSyntaxExceptions i Gson när du försöker deserialisera ett Jackson-formatdatum.

För att kringgå detta kan du lägga till en anpassad serienummer och en anpassad deserializer:

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

Att använda Gson med arv

Gson stöder inte arv utanför rutan.

Låt oss säga att vi har följande klasshierarki:

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

Och nu vill vi serialisera en instans av DerivedClass1 till en JSON-sträng

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

Nu, på ett annat ställe, får vi den här json-strängen och vill deserialisera den - men under sammanställningstiden vet vi bara att den ska vara en instans av BaseClass :

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

Men GSON vet inte derivedClass1Json var ursprungligen ett exempel på DerivedClass1 , så detta kommer att skriva ut 10.

Hur löser du detta?

Du måste bygga din egen JsonDeserializer , som hanterar sådana fall. Lösningen är inte helt ren, men jag kunde inte hitta en bättre lösning.

Lägg först till följande fält i din basklass

@SerializedName("type")
private String typeName;

Och initiera den i basklasskonstruktören

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

Lägg nu till följande klass:

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

Allt som finns kvar är att koppla upp allt -

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

Och nu kör följande kod-

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

Skriver ut 5.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow