当同步HashMap作为类成员时,Gson处理大小写

时间:2013-06-04 14:54:20

标签: java gson

我有一个将HashMap同步为类成员的情况。

public class Code {
    private Code(String code) {
        this.code = code;
    }

    public static Code newInstance(String code) {
        if (code == null) {
            throw new java.lang.IllegalArgumentException("code cannot be null");
        }

        return new Code(code);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + code.hashCode();

        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof Code)) {
            return false;
        }

        return this.code.equals(((Code)o).code);
    }

    @Override
    public String toString() {
        return code;
    }

    private String code;    
}

public class AlertStateManager {
    public boolean addFallBelow(Code code) {
        fallBelows.put(code, System.currentTimeMillis());
        return true;
    }

    public boolean addRiseAbove(Code code) {
        riseAboves.put(code, System.currentTimeMillis());
        return true;
    }

    public boolean removeFallBelow(Code code) {
        return fallBelows.remove(code) != null;
    }

    public boolean removeRiseAbove(Code code) {
        return riseAboves.remove(code) != null;
    }

    public void remove(Code code) {
        fallBelows.remove(code);
        riseAboves.remove(code);
    }

    public void remove() {
        fallBelows.clear();
        riseAboves.clear();
    }

    private final Map<Code, Long> fallBelows = java.util.Collections.synchronizedMap(new HashMap<Code, Long>());
    private final Map<Code, Long> riseAboves = java.util.Collections.synchronizedMap(new HashMap<Code, Long>());    
}

当我执行序列化和反序列化时,我得到以下内容

public static void main(String[] args) {
    AlertStateManager alertStateManager = new AlertStateManager();
    alertStateManager.addFallBelow(Code.newInstance("hello"));
    alertStateManager.addRiseAbove(Code.newInstance("world"));

    String json_alert_state_manager = null;
    // WRITE
    {
        final Gson gson = new Gson();
        json_alert_state_manager = gson.toJson(alertStateManager);
    }

    System.out.print(json_alert_state_manager);

    // READ
    {
        final Gson gson = new Gson();
        alertStateManager = gson.fromJson(json_alert_state_manager, AlertStateManager.class);
    }
}

序列化

{"fallBelows":{"hello":1370356891664},"riseAboves":{"world":1370356891664}}

反序列化

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 17
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
    at com.google.gson.Gson.fromJson(Gson.java:803)
    at com.google.gson.Gson.fromJson(Gson.java:768)
    at com.google.gson.Gson.fromJson(Gson.java:717)
    at com.google.gson.Gson.fromJson(Gson.java:689)
    at javaapplication6.JavaApplication6.main(JavaApplication6.java:38)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 17
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:374)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:165)
    ... 10 more
Java Result: 1

我能做些什么让它有效? 我正在使用Gson 2.2.3

2 个答案:

答案 0 :(得分:3)

@MikO提供了很好的提示。经过几次实验,我发现在序列化过程中,我们需要构建以下

        GsonBuilder builder = new GsonBuilder();
        builder.enableComplexMapKeySerialization();
        Gson gson = builder.create(); 

这将生成正确的json字符串。

{"fallBelows":[[{"code":"hello"},1370359852472]],"riseAboves":[[{"code":"world"},1370359852472]]}

请注意,在反序列化期间,为避免上述json字符串变为LinkedHashMap,这是我们需要做的事情

private static class SynchronizedMapInstanceCreator<K, V> implements
        InstanceCreator<Map<K, V>> {

    @Override
    public Map<K, V> createInstance(final Type type) {
        return java.util.Collections.synchronizedMap(new HashMap<K, V>());
    }
} 

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    String json_alert_state_manager = "{\"fallBelows\":[[{\"code\":\"hello\"},1370359852472]],\"riseAboves\":[[{\"code\":\"world\"},1370359852472]]}";
    // READ
    {
        Gson gson = new GsonBuilder().registerTypeAdapter(
            new TypeToken<Map<Code, Long>>() {}.getType(), 
            new SynchronizedMapInstanceCreator<Code, Long>()).create();
        AlertStateManager alertStateManager = gson.fromJson(json_alert_state_manager, AlertStateManager.class);
        alertStateManager.debug();
    }
}

答案 1 :(得分:1)

正如您告诉Gson它应该将"fallBelows"(以及"riseAboves")元素的内容解析为Map<Code, Long>,它预计会出现以下情况:

"fallBelows": { {codeObject}, someLong }

但它发现了这个:

"fallBelows": { "someString", someLong }

这就是为什么它抱怨说它已经消耗了一个对象(Code),但它发现了一个字符串......

编辑:我刚刚意识到这对你来说可能很清楚,但是在地图序列化中一定存在问题,我会尝试检查......