我的json对象里面有任意值。我想在Map中反序列化它。除了将整数转换为双打外,一切都很好。见例:
{"id":1, "inner_obj":{"key":"value","num":666,"map":{"key":"value"}}}
反序列化为此(map.toString()):
{id=1.0, inner_obj={key=value, num=666.0, map={key=value}}}
是否有一些简单的方法可以将“id”和“num”反序列化为整数而不是双打?
答案 0 :(得分:7)
JSON中没有整数类型。 1和1.0是相同的。您需要在代码中解析1.0到1。或者您需要将JSON映射到某个VO类并明确定义类的字段类型,以便GSON可以理解您要查找的内容。
答案 1 :(得分:2)
JSON只有一个Number类型,解析器无法自动告知将其转换为什么类型。
如果您不打算使用强类型对象图,请考虑使用JsonElement类型:
JsonObject root = new Gson().fromJson(json, JsonObject.class);
int num = root.getAsJsonObject("inner_obj").get("num").getAsInt();
答案 2 :(得分:1)
这是我的代码
private static class MapDeserializer implements JsonDeserializer<Map<String,Object>> {
public Map<String,Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Map<String,Object> m = new LinkedHashMap<String, Object>();
JsonObject jo = json.getAsJsonObject();
for (Entry<String, JsonElement> mx : jo.entrySet()){
String key = mx.getKey();
JsonElement v = mx.getValue();
if(v.isJsonArray()){
m.put(key, g.fromJson(v, List.class));
}else if(v.isJsonPrimitive()){
Number num = null;
try {
num = NumberFormat.getInstance().parse(v.getAsString());
} catch (Exception e) {
e.printStackTrace();
}
m.put(key,num);
}else if(v.isJsonObject()){
m.put(key,g.fromJson(v, Map.class));
}
}
return m;
}
}
private static class ListDeserializer implements JsonDeserializer<List<Object>> {
public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<Object> m = new ArrayList<Object>();
JsonArray arr = json.getAsJsonArray();
for (JsonElement jsonElement : arr) {
if(jsonElement.isJsonObject()){
m.add(g.fromJson(jsonElement, Map.class));
}else if(jsonElement.isJsonArray()){
m.add(g.fromJson(jsonElement, List.class));
}else if(jsonElement.isJsonPrimitive()){
Number num = null;
try {
num = NumberFormat.getInstance().parse(jsonElement.getAsString());
} catch (Exception e) {
}
m.add(num);
}
}
return m;
}
}
private static Gson g = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserializer()).registerTypeAdapter(List.class, new ListDeserializer()).setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create();
答案 3 :(得分:1)
我自己和#34;이종은&#34;正在寻找嵌套地图问题的解决方案。上面是第一个真正有助于非平凡用例的答案。
由于上面的解决方案只处理了Number I更新了解决方案,以便为String和booleans提供通用的解析功能,请参阅下面的更新代码:
private static class MapDeserializer implements JsonDeserializer<Map<String, Object>> {
public Map<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Map<String, Object> m = new LinkedHashMap<String, Object>();
JsonObject jo = json.getAsJsonObject();
for (Entry<String, JsonElement> mx : jo.entrySet()) {
String key = mx.getKey();
JsonElement v = mx.getValue();
if (v.isJsonArray()) {
m.put(key, g.fromJson(v, List.class));
} else if (v.isJsonPrimitive()) {
Number num = null;
ParsePosition position=new ParsePosition(0);
String vString=v.getAsString();
try {
num = NumberFormat.getInstance(Locale.ROOT).parse(vString,position);
} catch (Exception e) {
}
//Check if the position corresponds to the length of the string
if(position.getErrorIndex() < 0 && vString.length() == position.getIndex()) {
if (num != null) {
m.put(key, num);
continue;
}
}
JsonPrimitive prim = v.getAsJsonPrimitive();
if (prim.isBoolean()) {
m.put(key, prim.getAsBoolean());
} else if (prim.isString()) {
m.put(key, prim.getAsString());
} else {
m.put(key, null);
}
} else if (v.isJsonObject()) {
m.put(key, g.fromJson(v, Map.class));
}
}
return m;
}
}
private static class ListDeserializer implements JsonDeserializer<List<Object>> {
public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<Object> m = new ArrayList<Object>();
JsonArray arr = json.getAsJsonArray();
for (JsonElement jsonElement : arr) {
if (jsonElement.isJsonObject()) {
m.add(g.fromJson(jsonElement, Map.class));
} else if (jsonElement.isJsonArray()) {
m.add(g.fromJson(jsonElement, List.class));
} else if (jsonElement.isJsonPrimitive()) {
Number num = null;
try {
num = NumberFormat.getInstance().parse(jsonElement.getAsString());
} catch (Exception e) {
}
if (num != null) {
m.add(num);
continue;
}
JsonPrimitive prim = jsonElement.getAsJsonPrimitive();
if (prim.isBoolean()) {
m.add(prim.getAsBoolean());
} else if (prim.isString()) {
m.add(prim.getAsString());
} else {
m.add(null);
}
}
}
return m;
}
}
private static Gson g = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserializer()).registerTypeAdapter(List.class, new ListDeserializer()).setDateFormat("yyyy-MM-dd HH:mm:ss").create();
答案 4 :(得分:0)
这是我的例子,第一部分是具有int类型字段的类的定义。
import com.google.api.client.util.Key;
public class Folder {
public static final String FIELD_NAME_CHILD_COUNT = "childCount";
@Key(FIELD_NAME_CHILD_COUNT)
public final int childCount;
public Folder(int aChildCount) {
childCount = aChildCount;
}
}
然后使用TypeAdapter将Gson中的数字类型转换为Java对象。
GsonBuilder gsb = new GsonBuilder();
gsb.registerTypeAdapter(Folder.class, new JsonDeserializer<Folder>() {
@Override
public Folder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
int value = json.getAsJsonObject().get("childCount").getAsJsonPrimitive().getAsInt();
return new Folder(value);
}
}
);
第三部分是测试数据,它可以工作。
String gsonData = new String("\"folder\":{\"childCount\":0}");
答案 5 :(得分:0)
为避免可能的ClassCastException,最好先转换为Number
。在下面的代码中,map
从JSON反序列化为Map
,没有泛型。
int numberOfPages = ((Number) map.get("number_of_pages")).intValue();
答案 6 :(得分:0)
Map
的注册类型适配器:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Map.class, new JsonDeserializer<Map>() {
@Override
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
LinkedTreeMap<String,Object> m = new LinkedTreeMap<String, Object>();
JsonObject jo = json.getAsJsonObject();
for (Map.Entry<String, JsonElement> mx : jo.entrySet()){
String key = mx.getKey();
JsonElement v = mx.getValue();
if(v.isJsonArray()){
m.put(key, context.deserialize(v, List.class));
}else if(v.isJsonPrimitive()){
Object value = v.getAsString();
try {
Object numValue = NumberFormat.getInstance().parse((String)value);
if (numValue != null && numValue.toString().equals(value)) {
value = numValue;
}
} catch (Exception e) {
}
m.put(key, value);
}else if(v.isJsonObject()){
m.put(key,context.deserialize(v, Map.class));
}
}
return m;
}
})
.create();
并反序列化,例如:gson.fromJson(instanceJson, Map.class)
,其中instanceJson
是对象的json
,应反序列化为Map
。
答案 7 :(得分:0)
这是我解决问题的解决方案。我试图尽可能干净地实现它。我没有找到更好的简单解决方案来检查数字是否为整数。
public final class GSONUtil {
private GSONUtil() {
}
public static Gson createGson() {
// @formatter:off
return new GsonBuilder()
.registerTypeAdapter(Map.class, createMapDeserializer())
.registerTypeAdapter(List.class, createListDeserializer())
.create();
// @formatter:on
}
private static JsonDeserializer<Map<String,Object>> createMapDeserializer() {
return new JsonDeserializer<Map<String,Object>>() {
@Override
public Map<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsJsonObject().entrySet().stream() // stream
.collect(Collectors.toMap(Entry::getKey, (e) -> JSONUtil.deserialize(e.getValue(), context)));
}
};
}
private static JsonDeserializer<List<Object>> createListDeserializer() {
return new JsonDeserializer<List<Object>>() {
@Override
public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return StreamSupport.stream(json.getAsJsonArray().spliterator(), false) // stream
.map((e) -> JSONUtil.deserialize(e, context)).collect(Collectors.toList());
}
};
}
private static Object deserialize(JsonElement value, JsonDeserializationContext context) {
if (value.isJsonNull()) {
return null;
}
if (value.isJsonObject()) {
return context.deserialize(value, Map.class);
}
if (value.isJsonArray()) {
return context.deserialize(value, List.class);
}
if (value.isJsonPrimitive()) {
return parsePrimitive(value);
}
throw new IllegalStateException("This exception should never be thrown!");
}
private static Object parsePrimitive(JsonElement value) {
final JsonPrimitive jsonPrimitive = value.getAsJsonPrimitive();
if (jsonPrimitive.isString()) {
return jsonPrimitive.getAsString();
}
if (jsonPrimitive.isBoolean()) {
return jsonPrimitive.getAsBoolean();
}
if (jsonPrimitive.isNumber()) {
return parseNumber(jsonPrimitive);
}
throw new IllegalStateException("This exception should never be thrown!");
}
private static Number parseNumber(JsonPrimitive jsonPrimitive) {
if (isInteger(jsonPrimitive)) {
return jsonPrimitive.getAsLong();
}
return jsonPrimitive.getAsDouble();
}
private static boolean isInteger(final JsonPrimitive jsonPrimitive) {
return jsonPrimitive.getAsString().matches("[-]?\\d+");
}
}