Android
Gson
수색…
소개
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 구문 분석하기
이 예제는 Google 의 Gson 라이브러리를 사용하여 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 객체 typeListOfDogs
는 Dog
객체 목록이 어떻게 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가 인쇄됩니다.