수색…


소개

Gson 은 Java Object를 JSON 표현으로 변환하는 데 사용할 수있는 Java 라이브러리입니다. Gson은이 두 가지를 매우 중요한 디자인 목표로 간주합니다.

Gson 기능 :

간단한 toJson()fromJson() 메소드를 제공하여 Java 객체를 JSON으로 또는 그 반대로 변환합니다.

기존의 수정 불가능한 객체가 JSON으로 / JSON으로 변환되도록 허용

Java Generics의 광범위한 지원

임의로 복잡한 객체 지원 (깊은 상속 계층 구조와 일반적인 유형의 광범위한 사용)

통사론

  • Excluder excluder ()
  • FieldNamingStrategy 필드 NamingStrategy ()
  • <T> fromJson (JsonElement json, Class <T> classOfT)
  • <T> fromJson (JsonElement json, Type typeOfT)
  • <T> fromJson (JsonReader 리더, Type typeOfT)
  • <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 (Class <T> 유형)
  • <T> TypeAdapter <T> getAdapter (TypeToken <T> 유형)
  • <T> TypeAdapter <T> getDelegateAdapter (TypeAdapterFactory skipPast, TypeToken <T> 유형)
  • JsonReader newJsonReader (리더 판독기)
  • JsonWriter newJsonWriter (작성자 작가)
  • JsonElement toJsonTree (Object src)
  • JsonElement toJsonTree (Object src, Type typeOfSrc)
  • 부울 serializeNulls ()
  • 부울 htmlSafe ()
  • String toJson (JsonElement jsonElement)
  • String toJson (Object src)
  • String toJson (Object src, Type typeOfSrc)
  • String toString ()
  • void toJson (Object src, TypeOfSrc, 추가 가능한 라이터)
  • void toJson (Object src, TypeOfSrc 형, JsonWriter 라이터)
  • void toJson (JsonElement jsonElement, Appendable writer)
  • void toJson (JsonElement jsonElement, JsonWriter 작성자)
  • void toJson (Object src, 추가 가능한 라이터)

Gson으로 JSON 구문 분석하기

이 예제는 GoogleGson 라이브러리를 사용하여 JSON 객체를 파싱하는 방법을 보여줍니다.

객체 파싱 :

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


}

그런 다음 파싱이 필요한 곳에서 다음을 사용하십시오.

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

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

목록 구문 분석 :

JSON 객체의 목록을 검색 할 때 종종 구문을 분석하여 Java 객체로 변환해야합니다.

우리가 변환하려고하는 JSON 문자열은 다음과 같습니다.

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

이 특정 JSON 배열은 세 개의 객체를 포함합니다. Java 코드에서 이러한 객체를 Dog 객체에 매핑하려고합니다. Dog 객체는 다음과 같이 보입니다.

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

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

JSON 배열을 Dog[] :로 변환하려면 :

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

Dog[] 를 JSON 문자열로 변환 :

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

JSON 배열을 ArrayList<Dog> 로 변환하기 위해 다음을 할 수 있습니다 :

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

type 객체 typeListOfDogsDog 객체 목록이 어떻게 typeListOfDogs 정의합니다. GSON은이 유형 객체를 사용하여 JSON 배열을 올바른 값에 매핑 할 수 있습니다.

List<Dog> 를 JSON 배열로 변환하는 것도 비슷한 방법으로 수행 할 수 있습니다.

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

Gson으로 JSON 속성을 열거 형으로 구문 분석

Gson으로 열거 할 String을 구문 분석하려면 다음을 수행하십시오.

{ "status": "open"}

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

리스트 구문 분석하기 Gson과

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

이는 매개 변수가있는 유형의 클래스를 가져올 수 없으므로 (즉, List<String>.class 호출 할 수 없기 때문에) 대부분의 일반 컨테이너 클래스에 유용합니다.

방법 2

public class StringList extends ArrayList<String> { }

...

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

또는 언제든지 원하는 유형을 서브 클래 싱 한 다음 해당 클래스를 전달할 수 있습니다. 그러나 StringList 유형의 객체를 반환하기 때문에 항상 최선의 방법은 아닙니다.

AutoValue 및 Gson을 사용한 JSON 직렬화 / 직렬화 해제

귀하의 gradle 루트 파일에서 가져 오기

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

귀하의 gradle 응용 프로그램 파일에서 가져 오기

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'

자동 실행으로 객체 생성 :

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

GsonBuilder로 Gson 변환기 만들기

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

비 직렬화

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

일련 번호 지정

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

Gson을 사용하면 POJO 객체를 사용하여 직렬화 및 비 직렬화 코드를 단순화 할 수 있습니다. 부작용은 반영이 비용면에서 현명한 성과라는 것입니다. AutoValue-Gson을 사용하여 CustomTypeAdapter를 생성하면 API가 변경 될 때 매우 간단하게 업데이트하면서이 반영 비용을 피할 수 있습니다.

Gson을 사용하여 JSON을 일반 클래스 객체로 파싱하기

JSON 문자열이 있다고 가정합니다.

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

이 JSON 문자열을 String 배열로 파싱 할 수 있습니다.

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

그러나 List<String> 객체로 구문 분석하려면 TypeToken 을 사용해야합니다.

다음은 샘플입니다.

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

아래에 두 개의 클래스가 있다고 가정 해보십시오.

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

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

Outer<Person> 객체로 파싱되어야하는 JSON 문자열이 있습니다.

이 예제는이 JSON 문자열을 관련 제네릭 클래스 객체로 파싱하는 방법을 보여줍니다.

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

JSON 문자열을 Outer<List<Person>> 객체로 구문 분석해야하는 경우 :

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

프로젝트에 Gson 추가하기

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

Gson의 최신 버전을 사용하려면

아래 라인은 컴파일 할 때마다 gson 라이브러리의 최신 버전을 컴파일합니다. 버전을 변경할 필요가 없습니다.

장점 : 최신 기능, 속도 및 적은 버그를 사용할 수 있습니다.
단점 : 코드와의 호환성이 손상 될 수 있습니다.

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

Gson을 사용하여 디스크에서 JSON 파일로드

이렇게하면 디스크에서 JSON 파일을로드하고 지정된 유형으로 변환합니다.

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

Gson에 사용자 지정 변환기 추가하기

때로는 원하는 형식으로 일부 필드를 직렬화 또는 비 직렬화해야합니다. 예를 들어 백엔드는 날짜에 "YYYY-MM-dd HH : mm"형식을 사용할 수 있으며 POJOS에서 Joda Time에서 DateTime 클래스를 사용하게 할 수 있습니다.

이러한 문자열을 DateTimes 개체로 자동 변환하려면 사용자 지정 변환기를 사용할 수 있습니다.

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

Gson이 새로 생성 된 변환기를 사용하게하려면 Gson 객체를 만들 때 할당해야합니다.

    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

해당 형식으로 날짜를 비 직렬화하려면 DateTime 형식으로 필드를 정의하기 만하면됩니다.

public class SomePojo {
    private DateTime someDate;    
} 

Gson이 DateTime 형식의 필드를 발견하면 필드를 deserialize하기 위해 변환기를 호출합니다.

개량 기능을 갖춘 시리얼 라이저로 Gson 사용하기

먼저 GsonConverterFactory 를 build.gradle 파일에 추가해야합니다.

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

그런 다음 Retrofit Service를 만들 때 변환기 팩터 리를 추가해야합니다.

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

팩토리에 전달할 Gson 객체를 만들 때 사용자 정의 변환기를 추가 할 수 있습니다. 사용자 정의 유형 변환을 작성할 수 있습니다.

Gson을 사용하여 json 배열을 제네릭 클래스로 구문 분석

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

이 배열을 사용자 정의 트윗 (짹짹 목록 컨테이너) 객체로 수동으로 파싱 할 수 있지만 fromJson 메소드를 사용하면 더 쉽게 수행 할 수 있습니다.

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

아래에 두 개의 클래스가 있다고 가정 해보십시오.

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

json 배열을 구문 분석하기 만하면 구문 분석에 다음 코드를 사용할 수 있습니다.

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

Gson을 사용하는 사용자 정의 JSON 디시리얼라이저

예를 들어, /Date(1465935152)/ 와 같은 모든 사용자 정의 형식으로 모든 응답의 모든 날짜를 상상해보십시오. 그리고 모든 Json 날짜를 Java Date 인스턴스로 역 직렬화하는 일반 규칙을 적용하고자합니다. 이 경우 사용자 정의 Json Deserializer를 구현해야합니다.

json의 예 :

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

이 클래스가 아래와 같다고 가정 해보십시오.

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

사용자 정의 디시리얼라이저 :

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

그리고 사용법 :

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

날짜 형식을 사용하여 Jackson JSON 문자열 serialize 및 deserialize

이는 Gson Date 변환을 Jackson과 호환되도록하려는 경우에도 적용됩니다.

Jackson은 대개 Date를 "신기원에서 밀리 초"로 serialize하지만 Gson은 Aug 31, 2016 10:26:17 과 같은 읽을 수있는 형식을 사용하여 Date를 나타냅니다. Jackson 형식의 Date를 deserialize하려고하면 Gson의 JsonSyntaxExceptions가 발생합니다.

이를 피하기 위해 사용자 정의 직렬 변환기와 사용자 정의 직렬화기를 추가 할 수 있습니다.

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과 상속 사용하기

Gson은 상자에서 상속을 지원하지 않습니다.

다음과 같은 클래스 계층 구조가 있다고 가정 해 보겠습니다.

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

이제 DerivedClass1 인스턴스를 JSON 문자열로 직렬화하려고합니다.

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

자, 다른 곳에서 우리는이 json 문자열을 받고 그것을 deserialize하고 싶습니다. 그러나 컴파일 시간에는 BaseClass 의 인스턴스가되어야한다는 것을 알고 있습니다 :

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

그러나 GSON은 derivedClass1Json 이 원래 DerivedClass1 의 인스턴스 derivedClass1Json 때문에 10을 인쇄합니다.

어떻게 해결할 수 있을까요?

그런 경우를 처리하는 자신 만의 JsonDeserializer 합니다. 솔루션은 완벽하게 깨끗하지는 않지만 더 좋은 솔루션을 찾지 못했습니다.

먼저 기본 클래스에 다음 필드를 추가하십시오.

@SerializedName("type")
private String typeName;

그리고 그것을 기본 클래스 생성자에서 초기화하십시오.

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

이제 다음 클래스를 추가하십시오.

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

모두가 할 일이 남아 있습니다.

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

그리고 이제 다음 코드를 실행합니다.

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

5가 인쇄됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow