前言:平常開發中,與json打交道的機會不少,通常對象json轉都不會出現什麼問題,可是json轉對象就有可能出現問題了,今天就來講說json轉map致使int型轉換成double的問題json
public class MyType<T> {
public T gsonToMap(String strJson) {
return new Gson().fromJson(strJson, new TypeToken<T>() {
}.getType());
}
}
String json = "{\"identifier\":\"18111111111\",\"opType\":1,\"platform\":0}";
Map<String, Object> map = new MyType<Map<String, Object>>().gsonToMap(json);
複製代碼
接下來的操做你們都知道了,藉助於網絡平臺,因而乎找到幾種解決方式,細心的我發現有人評論解決他們的問題,看來有戲啊【手動滑稽】bash
一、須要gson解析的類型 , 重寫他的deserialize方法, 就是將其中json手動解析成map , 不對數據進行處理網絡
public HashMap<String,Object> gsonToMap(String strJson) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(
new TypeToken<HashMap<String,Object>>(){}.getType(),
new JsonDeserializer<HashMap<String, Object>>() {
@Override
public HashMap<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
HashMap<String, Object> hashMap = new HashMap<>();
JsonObject jsonObject = json.getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
hashMap.put(entry.getKey(), entry.getValue());
}
return hashMap;
}
}).create();
return gson.fromJson(strJson, new TypeToken<HashMap<String,Object>>() {
}.getType());
}
複製代碼
二、自定義TypeAdapter替代Gson默認的adapter(此處埋下伏筆【偷笑】)解決,自定義TypeAdapter以下:ide
public class MapTypeAdapter extends TypeAdapter<Object> {
private final TypeAdapter<Object> delegate = new Gson().getAdapter(Object.class);
@Override
public Object read(JsonReader in) throws IOException {
JsonToken token = in.peek();
switch (token) {
case BEGIN_ARRAY:
List<Object> list = new ArrayList<>();
in.beginArray();
while (in.hasNext()) {
list.add(read(in));
}
in.endArray();
return list;
case BEGIN_OBJECT:
Map<String, Object> map = new LinkedTreeMap<>();
in.beginObject();
while (in.hasNext()) {
map.put(in.nextName(), read(in));
}
in.endObject();
return map;
case STRING:
return in.nextString();
case NUMBER:
/**
* 改寫數字的處理邏輯,將數字值分爲整型與浮點型。
*/
double dbNum = in.nextDouble();
// 數字超過long的最大值,返回浮點類型
if (dbNum > Long.MAX_VALUE) {
return String.valueOf(dbNum);
}
// 判斷數字是否爲整數值
long lngNum = (long) dbNum;
if (dbNum == lngNum) {
return String.valueOf(lngNum);
} else {
return String.valueOf(dbNum);
}
case BOOLEAN:
return in.nextBoolean();
case NULL:
in.nextNull();
return null;
default:
throw new IllegalStateException();
}
}
@Override
public void write(JsonWriter out, Object value) throws IOException {
delegate.write(out,value);
}
}
複製代碼
public T gsonToMap(String strJson) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(new TypeToken<T>(){}.getType(),new MapTypeAdapter()).create();
return gson.fromJson(strJson, new TypeToken<T>() {
}.getType());
}
String json = "{\"identifier\":\"18111111111\",\"opType\":1,\"platform\":0}";
Map<String, Object> map = new MyType<Map<String, Object>>().gsonToMap(json);
複製代碼
public static Map<String, Object> gsonToMap(String strJson) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(new TypeToken<Map<String,Object>>(){}.getType(),new MapTypeAdapter()).create();
return gson.fromJson(strJson, new TypeToken<Map<String, Object>>() {
}.getType());
}
String json = "{\"identifier\":\"18111111111\",\"opType\":1,\"platform\":0}";
Map<String, Object> map = new MyType<Map<String, Object>>().gsonToMap(json);
複製代碼
上述方案的確是能夠解決個人問題,可是卻給我留下了疑問;本着知其然知其因此然的目的,以爲解決這些疑惑工具
一、關於泛型這裏就要提到 泛型擦除,及泛型只在編譯階段有效,運行時就無效了ui
public abstract class TypeAdapter<T>
複製代碼
二、int轉double,其實這是Gson在源碼中故意爲之的,其實不只是int,long也會轉化成double,接下來咱們去尋找證據this
處理double:
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
if (serializeSpecialFloatingPointValues) {
return TypeAdapters.DOUBLE;
}
return new TypeAdapter<Number>() {
@Override public Double read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return in.nextDouble();
}
@Override public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
double doubleValue = value.doubleValue();
checkValidFloatingPoint(doubleValue);
out.value(value);
}
};
}
處理float:
private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) {
if (serializeSpecialFloatingPointValues) {
return TypeAdapters.FLOAT;
}
return new TypeAdapter<Number>() {
@Override public Float read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return (float) in.nextDouble();
}
@Override public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
float floatValue = value.floatValue();
checkValidFloatingPoint(floatValue);
out.value(value);
}
};
}
複製代碼
public final class ObjectTypeAdapter extends TypeAdapter<Object> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings("unchecked")
@Override 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;
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 LinkedTreeMap<String, 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;
default:
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);
}
}
複製代碼
case NUMBER:
return in.nextDouble();
複製代碼