我有一些关于JSON反序列化的问题。背景:响应来自图形数据库(ArangoDB,因此它的JavaScript服务器端),我通常使用JavaScript客户端进行处理。这非常有效,特别是因为在查询图形数据时,对象的JavaScript概念已证明非常有用(对我而言)。 I. e。我可以以任何对某个特定端点有用的方式附加边和节点。
这一切都很好用,但我开始对服务器进行一些性能测试,并决定使用一个简单的Java应用程序。但是因为我没有真正强力打字,所以我无法解决这个问题。基本上我想要的是模仿JavaScript概念并将任何对象反序列化为Map。然后,我将使用列表作为List的相同机制和属性再次反序列化属性。这不需要在对象结构中体现出来,我会在临时变量中实现这一点(客户端性能无关紧要)。
问题是Gson没有反序列化(我知道,它不应该),f.e。
{"a": {"b":"c"}}
使用
private static final Type TYPE = new TypeToken<Map<String, String>>(){}.getType();
到地图“a” - &gt;“{\”b \“:\”c \“}”。
有没有办法让Gson这样做,还是我必须手动解析字符串添加引号并转义其他引号?
我真的不是RegEx的粉丝,所以感谢任何帮助。
提前致谢, 纳斯
答案 0 :(得分:1)
我现在似乎更了解你的问题。仍然不确定你的代码的真正目的,所以我想在这里做一些假设,因为评论太短。
不幸的是,Java静态类型本质并不能让你编写那些用JavaScript编写的短代码。但是,您可以遵循惯用的方式,或者进行某种解决方法。
为什么你不能使用new TypeToken<Map<String, String>>(){}.getType()
的原因是GSON期望总是解析一个普通的字符串到字符串映射(Map<String,String>
)。因此{"a": "b"}
很好,但{"a":{"b":"c"}}
不是。在解析这样的JSON时,您应该对每个映射值类型做出一些假设/期望。默认情况下,GSON使用Map<String, Object
目标类型的Map.class
映射,因此以下代码有效,您必须自己检查值类型,以检查是否可以更深入。
final Gson gson = new Gson();
final String json = "{\"a\": {\"b\":\"c\"}}";
@SuppressWarnings("unchecked")
final Map<String, Object> outerMap = gson.fromJson(json, Map.class);
@SuppressWarnings("unchecked")
final Map<String, String> innerMap = (Map<String, String>) outerMap.get("a");
out.println(innerMap.get("b"));
C
请注意上面的类型转换,只有(Map<String, String>) outerMap.get("a")
个孩子真的是a
时才能使用事实taht Map
(无论由于泛型的性质而无法参数化在Java)。
以下方式重新考虑您尝试反序列化的对象模型。但是,这种方式对你来说可能是一种矫枉过正,但它使得类型分析本身摆脱了手动类型检查。另一个缺点是它需要创建另外两个不同的地图(但至少它只做一次)。一个优点是你可以在&#34;节点和#34;之间进行分离。和&#34;价值观&#34;以或多或少的方式绘制地图。以下包装器实现失去了原始的Map<String, ...>
接口,但如果它没有问题,你可以让它实现它(它肯定需要在API完整性和性能/内存命中之间找到折衷方案)
final class Wrapper {
private final Map<String, String> values;
private final Map<String, Wrapper> wrappers;
private Wrapper(final Map<String, String> values, final Map<String, Wrapper> wrappers) {
this.values = values;
this.wrappers = wrappers;
}
static Wrapper wrap(final Map<String, ?> map) {
final Map<String, String> values = new LinkedHashMap<>();
final Map<String, Wrapper> wrappers = new LinkedHashMap<>();
for ( final Entry<String, ?> e : map.entrySet() ) {
final String key = e.getKey();
final Object value = e.getValue();
if ( value instanceof String ) {
values.put(key, (String) value);
} else if ( value instanceof Map ) {
@SuppressWarnings("unchecked")
final Map<String, ?> m = (Map<String, ?>) value;
wrappers.put(key, wrap(m));
} else {
throw new IllegalArgumentException("The value has inappropriate type: " + value.getClass());
}
}
return new Wrapper(values, wrappers);
}
String valueBy(final String key) {
return values.get(key);
}
Wrapper wrapperBy(final String key) {
return wrappers.get(key);
}
}
然后:
final Gson gson = new Gson();
final String json = "{\"a\": {\"b\":\"c\"}}";
@SuppressWarnings("unchecked")
final Map<String, ?> outerMap = (Map<String, ?>) gson.fromJson(json, Map.class);
final Wrapper outerWrapper = wrap(outerMap);
final Wrapper innerWrapper = outerWrapper.wrapperBy("a");
out.println(innerWrapper.valueBy("b"));
C
手动包装很好,但你可以做得更多&#34; Gson-ish&#34;使用包装器反序列化器:
final class WrapperDeserializer
implements JsonDeserializer<Wrapper> {
private final Gson backingGson;
private WrapperDeserializer(final Gson backingGson) {
this.backingGson = backingGson;
}
static JsonDeserializer<Wrapper> getWrapperDeserializer(final Gson backingGson) {
return new WrapperDeserializer(backingGson);
}
@Override
public Wrapper deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) {
@SuppressWarnings("unchecked")
final Map<String, ?> map = backingGson.fromJson(json, Map.class);
return wrap(map);
}
}
请注意,它使用支持Gson
实例来对Map
个实例进行deserilize(json.getAsJsonObject().entrySet()
将无效,因为它将包含JsonObject
个实例作为值,从而使{{1}没有任何真正原因的GSON感知方法 - 这就是为什么将它转换为&#34; native&#34; JDK类更好的原因。然后:
Wrapper.wrap
C
而且,作为结论,静态类型需要更多的工作,并且在某些情况下可能看起来不太方便。