Gson将对象的地图反序列化为字符串映射

时间:2016-10-31 18:17:45

标签: json serialization gson deserialization

我有一些关于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的粉丝,所以感谢任何帮助。

提前致谢, 纳斯

1 个答案:

答案 0 :(得分:1)

我现在似乎更了解你的问题。仍然不确定你的代码的真正目的,所以我想在这里做一些假设,因为评论太短。

不幸的是,Java静态类型本质并不能让你编写那些用JavaScript编写的短代码。但是,您可以遵循惯用的方式,或者进行某种解决方法。

简单Java

为什么你不能使用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

而且,作为结论,静态类型需要更多的工作,并且在某些情况下可能看起来不太方便。