android에서 Gson 라이브러리 사용

17747 단어 jsongson
1. 역서열화
1.public <T> T fromJson(String json, Class<T> classOfT)
2.public <T> T fromJson(String json, Type typeOfT)
3.public <T> T fromJson(Reader json, Class<T> classOfT)
4.public <T> T fromJson(Reader json, Type typeOfT)
5.public <T> T fromJson(JsonReader reader, Type typeOfT)
6.public <T> T fromJson(JsonElement json, Class<T> classOfT)
7.public <T> T fromJson(JsonElement json, Type typeOfT)
기본적으로 사용한 것은 제때에 이상의 몇 가지 방법이고 모두가 일반적으로 사용하는 것은 앞의 두 가지 방법이다.
첫 번째 방법에서는 패키지 유형과 사용자 정의 솔리드 유형만 기본 객체 유형으로 해석할 수 있습니다.
Student student = gson.fromJson(s1, Student.class);
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson(""abc"", String.class);
String anotherStr = gson.fromJson("["abc"]", String.class);
그리고 구체적인 해석 과정을 살펴보자.
1. 여기서 Class 유형을 Type 유형으로 강제로 바꾼 다음 fromJson 방법을 호출합니다.
 public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
    Object object = fromJson(json, (Type) classOfT);
    return Primitives.wrap(classOfT).cast(object);
  }

2. json 문자열을 StringReader로 봉한 다음 fromJson 메서드를 호출합니다.
  public <T> 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;
  }
3.StringReader를 JsonReader로 포장한 다음 FromJson 메서드를 호출합니다.
 public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    JsonReader jsonReader = new JsonReader(json);
    T object = (T) fromJson(jsonReader, typeOfT);
    assertFullConsumption(object, jsonReader);
    return object;
  }
4.마지막으로 호출된 방법은 다음과 같습니다.
 public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient();
    reader.setLenient(true);
    try {
      reader.peek();
      isEmpty = false;
      TypeAdapter<T> typeAdapter = (TypeAdapter<T>) getAdapter(TypeToken.get(typeOfT));
      return typeAdapter.read(reader);
    } catch (EOFException e) {
      /*
       * For compatibility with JSON 1.5 and earlier, we return null for empty
       * documents instead of throwing.
       */
      if (isEmpty) {
        return null;
      }
      throw new JsonSyntaxException(e);
    } catch (IllegalStateException e) {
      throw new JsonSyntaxException(e);
    } catch (IOException e) {
      // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
      throw new JsonSyntaxException(e);
    } finally {
      reader.setLenient(oldLenient);
    }
  }
이 방법에서 GetAdapter 방법을 통해 typeOft 유형에 대응하는 TypeAdapter 대상을 얻을 수 있는데 구체적으로 어떻게 얻을 수 있습니까?다음 보기:
5. 캐시된 맵에서 TypeAdapter 대상을 가져오고 없으면 아래factories 공장 집합을 옮겨다니며
 public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    TypeAdapter<?> cached = typeTokenCache.get(type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }

    Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
    // the key and value type parameters always agree
    FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }

    FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
    threadCalls.put(type, call);
    try {
      for (TypeAdapterFactory factory : factories) {
        TypeAdapter<T> 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);
    }
  }
6.다음은 gson의 구조 함수에서 초기화된factories 집합에 대응하는 대상 유형의 TypeAdapter 대상을 만드는 공장을 추가하는 것을 보십시오.
 // built-in type adapters that cannot be overridden
    factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
    factories.add(ObjectTypeAdapter.FACTORY);

    // 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);
    factories.add(TypeAdapters.newFactory(long.class, Long.class,
            longAdapter(longSerializationPolicy)));
    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.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.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.ENUM_FACTORY);
    factories.add(TypeAdapters.CLASS_FACTORY);

    // the excluder must precede all adapters that handle user-defined types
    factories.add(excluder);

    // type adapters for composite and user-defined types
    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
    factories.add(new ReflectiveTypeAdapterFactory(
        constructorConstructor, fieldNamingPolicy, excluder));

    this.factories = Collections.unmodifiableList(factories);
예를 들어 기본적인 TypeAdapter 대상의 공장은 모두 TypeAdapters 클래스에 위치하고 여기서 예를 들어 TypeAdapters를 볼 수 있다.STRING_FACTORY 공장:
 public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
public static <TT> TypeAdapterFactory newFactory(
      final Class<TT> type, final TypeAdapter<TT> typeAdapter) {
    return new TypeAdapterFactory() {
      @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
      }
      @Override public String toString() {
        return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]";
      }
    };
  }

사용자 정의 실체 유형이라면, 사용하는 TypeAdapters는 ObjectTypeAdapter입니다.FACTORY:
public final class ObjectTypeAdapter extends TypeAdapter<Object> {
  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
    @SuppressWarnings("unchecked")
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      if (type.getRawType() == Object.class) {
        return (TypeAdapter<T>) new ObjectTypeAdapter(gson);
      }
      return null;
    }
  };

  private final Gson gson;

  private ObjectTypeAdapter(Gson gson) {
    this.gson = gson;
  }

  @Override public Object read(JsonReader in) throws IOException {
    JsonToken token = in.peek();
    switch (token) {
    case BEGIN_ARRAY:
      List<Object> list = new ArrayList<Object>();
      in.beginArray();
      while (in.hasNext()) {
        list.add(read(in));
      }
      in.endArray();
      return list;

    case BEGIN_OBJECT:
      Map<String, Object> map = new StringMap<Object>();
      in.beginObject();
      while (in.hasNext()) {
        map.put(in.nextName(), read(in));
      }
      in.endObject();
      return map;

    case STRING:
      return in.nextString();

    case NUMBER:
      return in.nextDouble();

    case BOOLEAN:
      return in.nextBoolean();

    case NULL:
      in.nextNull();
      return null;

    }
    throw new IllegalStateException();
  }

  @SuppressWarnings("unchecked")
  @Override public void write(JsonWriter out, Object value) throws IOException {
    if (value == null) {
      out.nullValue();
      return;
    }

    TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());
    if (typeAdapter instanceof ObjectTypeAdapter) {
      out.beginObject();
      out.endObject();
      return;
    }

    typeAdapter.write(out, value);
  }
}
여기가 BEGIN이라면ARRAY나 BEGINOBJECT 유형은 모두 하위 집합이나 하위 대상이 있을 수 있습니다. 대상이라면 키-value로 맵에 저장하고 집합이면 집합으로 돌아갑니다.다음은 STRING, NUMBER(double, long, int), BOOLEAN(true or false), NULL(null) 유형일 수도 있습니다.
이렇게 하면 대응하는 공장을 만들고,create 방법의 호출이야말로TypeAdapter 대상을 만든다. 여기서 getadapter 방법의 for 순환으로 돌아가고, 마지막으로 위의read 방법을 호출하여 반서열화한다.
다음은 TypeAdapter 사용을 살펴보겠습니다.
여러분은 그의read와 write 방법을 다시 써서 자신이 정의한 유형에 대한 해석을 할 수 있습니다. 예를 들어 서버에서 요청한 데이터, 이 데이터는 하나의 대상 중의 두 필드로 전환해야 합니다. 이read에서는 이렇게 조작할 수 있습니다. 예를 들어 공식적인 예,
public class PointAdapter extends TypeAdapter<Point> {
    public Point read(JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
            reader.nextNull();
            return null;
        }
        String xy = reader.nextString();
        String[] parts = xy.split(",");
        int x = Integer.parseInt(parts[0]);
        int y = Integer.parseInt(parts[1]);
        return new Point(x, y);
    }

    public void write(JsonWriter writer, Point value) throws IOException {
        if (value == null) {
            writer.nullValue();
            return;
        }
        String xy = value.getX() + "," + value.getY();
        writer.value(xy);
    }
}
만약read와 write에서null의 상황을 검사했다면 다음과 같이 사용합니다.
GsonBuilder builder = new GsonBuilder(); 
builder.registerTypeAdapter(Point.class, new PointAdapter());
Gson gson = builder.create();
수동으로 null 검사를 하지 않으면 다음을 사용합니다.
builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());

다음은 시스템의 기본 구현입니다.
DateTypeAdapter.java
예를 들어 당신의 실체류에 정의된java가 있습니다.util.Date 패키지 종류의date 형식입니다. 그러면 역서열화할 때 DateTypeAdapter를 사용하여date 형식으로 변환할 필드를 조작합니다.
  @Override public Date read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    return deserializeToDate(in.nextString());
  }

  private synchronized Date deserializeToDate(String json) {
    try {
      return localFormat.parse(json);
    } catch (ParseException ignored) {
    }
    try {
      return enUsFormat.parse(json);
    } catch (ParseException ignored) {
    }
    try {
      return iso8601Format.parse(json);
    } catch (ParseException e) {
      throw new JsonSyntaxException(json, e);
    }
  }
그러나 이때 서버가 빈 문자로 되돌아오면 전환이 이상을 보고합니다. 앞의 두 가지 전환이 모두 포착되고 아무런 처리도 하지 않기 때문에 마지막으로throw new Json Syntax Exception(json, e)을 사용합니다.프로그램을 붕괴시키기 위해 이상을 던지기:
그러니 이쪽에서 이상을 판단하고 포착하는 것이 좋다. 예를 들어:
 GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        @Override
        public Date deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
                throws JsonParseException {
            try {
                return df.parse(json.getAsString());
            } catch (ParseException e) {
                return null;
            }
        }
    });
    Gson gson = gsonBuilder.create();
이렇게 하면 이상이 생기면 포착하고null로 돌아갑니다.
TimeTypeAdapter.java
만약 실체 클래스에java가 정의되어 있다면.sql.Time의 Time 유형입니다. 그러면 역서열화할 때 TimeTypeAdapter를 사용하여 Time 유형으로 변환할 필드를 조작합니다.
  private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");

  @Override public synchronized Time read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    try {
      Date date = format.parse(in.nextString());
      return new Time(date.getTime());
    } catch (ParseException e) {
      throw new JsonSyntaxException(e);
    }
  }

  @Override public synchronized void write(JsonWriter out, Time value) throws IOException {
    out.value(value == null ? null : format.format(value));
  }

SqlDateTypeAdapter.java
만약 실체 클래스에java가 정의되어 있다면.sql.Date의 Date 유형입니다. 그러면 역정렬할 때 SqlDateTypeAdapter를 사용하여 Date 유형으로 변환할 필드를 조작합니다.
 private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");

  @Override
  public synchronized java.sql.Date read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    try {
      final long utilDate = format.parse(in.nextString()).getTime();
      return new java.sql.Date(utilDate);
    } catch (ParseException e) {
      throw new JsonSyntaxException(e);
    }
  }

  @Override
  public synchronized void write(JsonWriter out, java.sql.Date value) throws IOException {
    out.value(value == null ? null : format.format(value));
  }

ArrayTypeAdapter.java
실체의 집합이나 그룹을 이 종류로 필터합니다.
MapTypeAdapterFactory.java의 어댑터 내부 클래스
실체의 맵 대상은 이 종류로 필터합니다.
TreeTypeAdapter.java
Json Serializer와 Json Deserializer가 클래스를 실현하는 방법을 간접적으로 호출합니다.
JsonDeserializer 인터페이스 사용:
기본적으로 인터페이스는 DefaultDateTypeAdapter 클래스 하나에 대해서만 구현됩니다. 이 클래스는 주로 다음 세 가지 방법을 설정한 경우에만 적용됩니다.
public GsonBuilder setDateFormat(String pattern)
public GsonBuilder setDateFormat(int style)
public GsonBuilder setDateFormat(int dateStyle, int timeStyle)
다음과 같은 방법으로 확인할 수 있습니다.
 private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
      List<TypeAdapterFactory> factories) {
    DefaultDateTypeAdapter dateTypeAdapter;
    if (datePattern != null && !"".equals(datePattern.trim())) {
      dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);
    } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
      dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);
    } else {
      return;
    }

    factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Date.class), dateTypeAdapter));
    factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Timestamp.class), dateTypeAdapter));
    factories.add(TreeTypeAdapter.newFactory(TypeToken.get(java.sql.Date.class), dateTypeAdapter));
  }

장면 적용:
public class Foo {

    Date date;
    Date created_at;

    public Foo(Date date, Date created_at){
       this.date = date;
       this.created_at = created_at;
    }

    @Override
    public String toString() {
       return "Foo [date=" + date + ", created_at=" + created_at + "]";
    }

}
public class FooDeserializer implements JsonDeserializer<Foo> {

     public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        String a = json.getAsJsonObject().get("date").getAsString();
        String b = json.getAsJsonObject().get("created_at").getAsString();

        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdfDateWithTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

        Date date, created;
        try {
           date = sdfDate.parse(a);
           created = sdfDateWithTime.parse(b);
        } catch (ParseException e) {
           throw new RuntimeException(e);
        }

        return new Foo(date, created);
    }

}
같은 Date 유형이라도 다른 형식으로 변환할 수 있음(TypeAdapter를 사용해도 마찬가지)
컬렉션 또는 맵 객체의 경우 다음과 같이 써야 합니다.
map:[[{"x":5,"y":6},"a"],[{"x":8,"y":8},"b"]]
Map<Point, String> retMap = gson.fromJson(s, new TypeToken<Map<Point, String>>() {}.getType());
list:
List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType());

좋은 웹페이지 즐겨찾기