Gson 프레임 워 크 학습
소개 하 다.
Gson (일명 구 글 Gson) 은 구 글 이 발표 한 오픈 소스 코드 자바 라 이브 러 리 로 자바 대상 을 JSON 문자열 로 정렬 하거나 JSON 문자열 을 자바 대상 으로 역 직렬 화 하 는 데 사용 된다.
기본 개념
JsonPrimitive ——
JsonObject—— JsonElement ( String) 。 JsonObject JsonElement 。
JsonArray—— JsonElement 。 , 。
JsonNull—— null
질문
gson 주해
소스 코드 분석
Gson 은 사실 모델 변환 도구 입 니 다. 그의 한쪽 은 json 데이터 형식 인 코딩 흐름 이 고 다른 한쪽 은 우리 의 자바 대상 모델 입 니 다.우 리 는 먼저 자신 에 게 입구 점 을 찾 아 Gson 에서 흔히 볼 수 있 는 예 를 보 자.
public static class ClassRoom {
public String roomName;
public int number;
public String toString() {
return "[" + roomName + ":" + number + "]";
}
}
public static class User {
public String name;
public int age;
private ClassRoom room;
@Override
public String toString() {
// TODO Auto-generated method stub
return name + "->" + age + ":" + room;
}
}
우 리 는 json 형식의 데이터 문자열 을 전송 하려 고 시도 했다.
Gson gson = new Gson();
String strJson = "{name:'david',age:19,room:{roomName:'small',number:1}}";
User u = gson.fromJson(strJson, User.class);
상기 코드 에서 gson 은 데이터 어댑터 의 역할 을 하고 JSon 의 데이터 형식 을 자바 업무 에 사용 할 수 있 는 데이터 모델 로 변환 하 는 것 과 같다.이 층 의 전환 은 Gson 의 from JSon 방법 을 통 해 이 루어 졌 다.
public T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
Gson 은 스 트림 방식 으로 문 자 를 읽 는 것 을 지원 합 니 다. 인터페이스의 재 활용 성 을 위해 첫 번 째 매개 변 수 를 String 대상 으로 입력 하면 Gson 처럼 스 트림 대상 StringReader 로 포장 합 니 다.Gson 의 from JSon 은 통 일 된 인터페이스 방법 T from JSon (Json Reader reader, Type type: OfT) 으로 호출 됩 니 다.
//code 2
public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);// Json
try {
reader.peek();
isEmpty = false;
TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
TypeAdapter typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
............
}
}
code 2 코드 에서 주로 다음 과 같은 일 을 했 습 니 다.
//code3
public JsonToken peek() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
....
}
peek 방법 은 이전 스 트림 파일 처럼 실제 데 이 터 를 되 돌려 주 는 것 이 아니 라 현재 의 분석 상태 표지 인 JsonToken 을 되 돌려 줍 니 다.JSonToken 은 매 거 진 유형 으로 JSon 데이터 형식 에 표 시 된 각종 문법 단위 입 니 다.peek () 함수 내부 에서 doPeek () 를 호출 했 습 니 다.두 이름 은 똑 같 았 지만 돌아 온 결 과 는 전혀 달 랐 다.doPeek 은 진정한 의미 에서 데 이 터 를 되 돌려 주 는 것 입 니 다. 즉, 진실 한 문 자 를 되 돌려 주 는 것 입 니 다.
//code doPeek()
private int doPeek() throws IOException {
stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
switch (c) {
case '"':
return peeked = PEEKED_DOUBLE_QUOTED_NAME;
case '\'':
checkLenient();
return peeked = PEEKED_SINGLE_QUOTED_NAME;
case '}':
if (peekStack != JsonScope.NONEMPTY_OBJECT) {
return peeked = PEEKED_END_OBJECT;
} else {
throw syntaxError("Expected name");
}
default:
}
}
doPeek () 함수 에 stack 변수 라 는 데 이 터 를 사용 해 야 합 니 다. 그 안에 저 장 된 것 은 JsonScope 라 는 상수 입 니 다.이것 은 Gson 이 JSon 에 대한 분석 방식 은 스 택 식 해석 을 사용 하고 차원 에 따라 분석 하 는 방식 이기 때문에 이런 차원 의 분석 방식 은 스 택 으로 이전의 상 태 를 기록 해 야 하기 때문이다.이 stack 의 초기 값 은 초기 코드 블록 에 설정 되 어 있 습 니 다:
private int[] stack = new int[32];
public int stackSize = 0;
{
stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
}
이 를 통 해 알 수 있 듯 이 stack 초기 스 택 지붕 데 이 터 는 EMPTY 입 니 다.DOCUMENT 상수.이때 우 리 는 doPeek 함수 로 돌아 갔다.우 리 는 볼 수 있다.
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
switch (p) {
case PEEKED_BEGIN_OBJECT:
return JsonToken.BEGIN_OBJECT;
}
doPeek 방법 은 정형 의 상수 로 되 돌아 간 후 peek 방법 은 이 정형 상수 로 대응 하 는 JSonToken 변수 로 바 뀌 었 습 니 다. 어떤 관리 들 은 물 어 볼 수도 있 습 니 다. 그렇다면 JSonToken 의 의 미 는 무엇 입 니까? JSonToken 의 데 이 터 를 되 돌아 오 는 peeked 변수 로 대체 할 수 있 습 니까?
case PEEKED_SINGLE_QUOTED_NAME:
case PEEKED_DOUBLE_QUOTED_NAME:
case PEEKED_UNQUOTED_NAME:
return JsonToken.NAME;
우 리 는 세 가지 peek 에서 나 온 데이터 형식 을 볼 수 있 습 니 다. 실제 적 으로 Json 의 식별 자 에 대응 할 수 있 습 니 다. 그러면 peek 에서 나 온 기호 유형 (정형 상수) 과 Json 의 식별 자 (JsonToken 매 거 상수) 는 실제 적 으로 다 중 대응 하 는 수치 관계 이기 때문에 혼용 할 수 없습니다. 또한 우 리 는 peek () 에서방법 에서 생 성 된 이 JsonToken 은 Reader 에 기록 되 어 있 지 않 습 니 다. 즉, 데이터 에 대한 분석 에 있어 Reader 는 doPeek 방법 에서 생 성 된 중간 상태 데이터 에 관심 이 있 습 니 다.
code 2 로 돌아 갑 니 다. 위의 분석 에 따 르 면 reader. peek () 방법 은 실제 적 으로 데이터 변 수 를 초기 화 한 것 임 을 알 고 있 습 니 다. 이 어 from JSon 방법 은 TypeToken. get 의 정적 방법 으로 TypeToken 대상 을 생 성 합 니 다.
public static TypeToken> get(Type type) {
return new TypeToken
TypeToken 의 get 방식 은 정적 구조 공장 으로 TypeToken 대상 을 직접 되 돌려 줍 니 다.
Gson gson = new Gson();
String strJson = "{name:'david',age:19,room:{roomName:'small',number:1}}";
User u = gson.fromJson(strJson, User.class);
TypeToken. get (User. class) 을 되 돌 릴 때 내부 에 User. class 를 Type 으로 하 는 TypeToken 변 수 를 가지 고 있 습 니 다. TypeToken. get (Type) 을 통 해방법 이 호출 되면 getAdapter 라 는 방법 으로 typeAdapter 대상 을 얻 을 수 있 습 니 다. TypeAdapter 는 Gson 코드 시스템 의 중요 한 부분 으로 진정한 의미 의 전환 작업 을 맡 았 습 니 다. Gson 은 Adapter 관리 에 있어 서 향 원 을 이용 하 였 습 니 다. 분석 류 구 조 는 일정한 시간 소 모 를 가지 고 있 기 때문에 이러한 시간 비용 을 낮 추기 위해 Gson 은 버퍼 를 사용 하여 관리 하 였 습 니 다.매 핑 관계. 아마도 독자 에 게 질문 이 있 을 것 입 니 다. TypeToken. get 방법 은 매번 정적 공장 의 방식 으로 새로운 TypeToken 을 구성 하 는 것 입 니 다. 그러면 cache 에 넣 으 면 cache 의 역할 을 하지 못 합 니까? 답 은: 네. 이 질문 에 대답 하려 면 TypeToken 의 소스 코드 로 돌아 가 야 합 니 다.
@Override
public final int hashCode() {
return this.hashCode;
}
@Override
public final boolean equals(Object o) {
return o instanceof TypeToken> && $Gson$Types.equals(type, ((TypeToken>) o).type);
}
위 코드 에 따 르 면 TypeToken 은 같은 hashCode 와 복사 한 equals 방법 으로 서로 다른 대상 의 충돌 문 제 를 해결 합 니 다. 좋 습 니 다. getAdapter 방법 으로 계속 돌아 가 겠 습 니 다.
// code Gson.getAdapter
public TypeAdapter getAdapter(TypeToken type) {
TypeAdapter> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null) {
return (TypeAdapter) cached;
}
Map, FutureTypeAdapter>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap, FutureTypeAdapter>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter call = new FutureTypeAdapter();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
cache 에 필요 한 어댑터 가 존재 하지 않 을 때, 버퍼 대상 이 존재 하지 않 을 때, Gson 은 맵 대상 을 만들어 라인 에 넣 습 니 다. 또한 Gson 의 Cache 특징 도 발견 할 수 있 습 니 다.
//
FutureTypeAdapter call = new FutureTypeAdapter();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
Adapter 의 구 조 는 하나의 factories 집합 클래스 를 옮 겨 다 니 며 이 루어 집 니 다. 방법 도 간단 합 니 다. Factory 는 들 어 오 는 TypeToken 형식 과 일치 하 는 지, 일치 하 는 지 여 부 를 통 해 대상 을 생 성 합 니 다. 일치 하지 않 으 면 null 로 돌아 갑 니 다. 또한 Adapter 대상 이 생 성 되면 구조 대상 이 우선 순위 가 있 음 을 설명 합 니 다. AFactory 는 규칙 을 통 해 대상 을 생 성 할 수 있 습 니 다. BFactory 는 규칙 을 통 해 대상 을 생 성 할 수 있 습 니 다. 이 럴 때 AFactory 가 BFactory 앞 에 있 으 면 AFactory 를 우선 사용 하여 Adapter 를 구성 합 니 다. factories 의 초기 화 데 이 터 는 Gson 의 구조 기 에 있 습 니 다.
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
final Map> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy,
List typeAdapterFactories)
{
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);// JsonElement
factories.add(ObjectTypeAdapter.FACTORY);// Object
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);//
// user's type adapters
factories.addAll(typeAdapterFactories);
// type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
TypeAdapter longAdapter = longAdapter(longSerializationPolicy);
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
factories.add(TypeAdapters.newFactory(double.class, Double.class,
doubleAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.newFactory(float.class, Float.class,
floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
factories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
factories.add(TypeAdapters.URL_FACTORY);
factories.add(TypeAdapters.URI_FACTORY);
factories.add(TypeAdapters.UUID_FACTORY);
factories.add(TypeAdapters.CURRENCY_FACTORY);
factories.add(TypeAdapters.LOCALE_FACTORY);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);
factories.add(TimeTypeAdapter.FACTORY);
factories.add(SqlDateTypeAdapter.FACTORY);
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
factories.add(TypeAdapters.CLASS_FACTORY);
// type adapters for composite and user-defined types
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this.factories = Collections.unmodifiableList(factories);
}
"User. class 유형 이 들 어 왔 을 때 Gson 은 Reflective TypeAdapter Factory 공장 을 통 해 Adapter 를 생산 하여 JSon 대상 에 적합 합 니 다.
public TypeAdapter create(Gson gson, final TypeToken type) {
Class super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {//
return null; // it's a primitive!
}
ObjectConstructor constructor = constructorConstructor.get(type);//
return new Adapter(constructor, getBoundFields(gson, type, raw));
}
기타
Gson gson = new GsonBuilder()
// null
.serializeNulls()
// , 2
//
.setDateFormat("yyyy-MM-dd")
//
.disableInnerClassSerialization()
// Json( )]}' 4 )
.generateNonExecutableJson()
// html
.disableHtmlEscaping()
//
.setPrettyPrinting()
.create();
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.