Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java GSON无法反序列化它以前序列化的对象:应为BEGIN\u对象,但为字符串_Java_Json_Gson - Fatal编程技术网

Java GSON无法反序列化它以前序列化的对象:应为BEGIN\u对象,但为字符串

Java GSON无法反序列化它以前序列化的对象:应为BEGIN\u对象,但为字符串,java,json,gson,Java,Json,Gson,这是一个狭义的例子,非常荒谬,但却说明了问题所在 以下代码: import java.util.*; import com.google.gson.*; class X {} class SomeType { private Map <X, String> map; public SomeType() { this.map = new HashMap<X, String>(); map.put(new X(), "b"

这是一个狭义的例子,非常荒谬,但却说明了问题所在

以下代码:

import java.util.*;
import com.google.gson.*;

class X {}

class SomeType {
    private Map <X,  String> map;
    public SomeType() {
        this.map = new HashMap<X, String>();
        map.put(new X(), "b");
    }
}

public class FooMain {

    private static Gson gson = new GsonBuilder().serializeNulls().create();

    public static void main(String args[]) throws Exception {
        String foo = gson.toJson(new SomeType(), SomeType.class);
        System.out.println(foo);                           // line 20
        SomeType st = gson.fromJson(foo, SomeType.class);  // line 21
    }
}
而第20行打印:

{"map":{"X@185b10b":"b"}}

Gson
通过使用键作为JSON键和Map元素的值作为值来序列化
Map
。因为您的
X
类没有自定义重写的
toString()
方法,所以它使用
对象#toString()
并将其序列化为
X@185b10b
但无法对其进行反序列化。即使您提供了
toString()
,它实际上也无法对其进行反序列化


我想您已经发现了一种边缘情况,无法正确序列化所有内容。JSON对象的键必须是
字符串

Ok,因此感谢Sotirios Delimanolis的回答,我发现了以下内容:

  • 您只能为
    Map
    key类提供自定义反序列化器。在这种情况下,该键类的
    toString
    方法必须提供“序列化”格式

  • 您可以为
    Map
    类本身提供一个通用适配器(序列化器+反序列化器),并为
    Map
    键类提供一个通用适配器(序列化器+反序列化器)。这种方法的唯一优点是,key类的
    toString
    方法可以用于其他目的,而不必与反序列化器一起使用

以下是第二种情况的完整代码:

import java.util.*;
import com.google.gson.*;
import java.lang.reflect.Type;

import org.apache.commons.lang3.StringUtils;

class X {
    public int x;
    public X(int x) {
        this.x = x;
    }
    public String toString() {
        return String.format("boo ha ha %d", x);
    }
}

class SomeType {
    private Map <X,  String> map;
    public SomeType() {
        this.map = new HashMap<X, String>();
        map.put(new X(2), "b");
    }
    public String toString() {
        List<String> rv = new ArrayList<>();
        for (X x : map.keySet())
            rv.add(String.format("%s -> %s\n", x.toString(), map.get(x)));
        return StringUtils.join(rv, "\n");
    }
}

public class FooMain {

    public static void main(String args[]) throws Exception {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(X.class, new XAdapter());
        gsonBuilder.registerTypeAdapter(Map.class, new MapAdapter());
        Gson gson = gsonBuilder.serializeNulls().create();
        SomeType original = new SomeType();
        System.out.println("original is: "+original);
        String foo = gson.toJson(original, SomeType.class);
        System.out.println("JSON form is: "+foo);                     
        SomeType reconstructed = gson.fromJson(foo, SomeType.class);  
        System.out.println("reconstructed is: "+reconstructed);
    }
}


class MapAdapter implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {

    @Override
    public JsonElement serialize(Map<?, ?> m, Type typeOfT, JsonSerializationContext context) {
        JsonArray rv = new JsonArray();
        for (Object k : m.keySet()) {
            JsonObject kv = new JsonObject();
            kv.add        ("k"     , context.serialize(k));
            kv.addProperty("ktype" , k.getClass().getName());
            kv.add        ("v"     , context.serialize(m.get(k)));
            kv.addProperty("vtype" , m.get(k).getClass().getName());
            rv.add(kv);
        }
        return rv;
    }

    @Override
    public Map<?, ?> deserialize(JsonElement _json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonArray json = (JsonArray) _json;
        Map<Object, Object> rv = new HashMap<>();
        for (int i = 0 ; i < json.size() ; i++) {
            JsonObject o = (JsonObject) json.get(i);
            String ktype = o.getAsJsonPrimitive("ktype").getAsString();
            String vtype = o.getAsJsonPrimitive("vtype").getAsString();
            Class<?> kklass = null;
            Class<?> vklass = null;
            try {
                kklass = Class.forName(ktype);
                vklass = Class.forName(vtype);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new JsonParseException(e.getMessage());
            }
            Object k = context.deserialize( o.get("k"), kklass);
            Object v = context.deserialize( o.get("v"), vklass);
            rv.put(k, v);
        }
        return rv;
    }

}


class XAdapter implements JsonSerializer<X>, JsonDeserializer<X> {

    @Override
    public JsonElement serialize(X x, Type typeOfT, JsonSerializationContext context) {
        return context.serialize(x.x);
    }

    @Override
    public X deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        String s = json.getAsString();
        int x = Integer.valueOf(s);
        return new X(x);
    }
}
import java.util.*;
导入com.google.gson.*;
导入java.lang.reflect.Type;
导入org.apache.commons.lang3.StringUtils;
X类{
公共int x;
公共X(int X){
这个.x=x;
}
公共字符串toString(){
返回String.format(“boo-ha-ha%d”,x);
}
}
类SomeType{
私人地图;
公共类型(){
this.map=新的HashMap();
地图放置(新X(2),“b”);
}
公共字符串toString(){
List rv=新的ArrayList();
对于(X:map.keySet())
add(String.format(“%s->%s\n”,x.toString(),map.get(x));
返回StringUtils.join(rv,“\n”);
}
}
公共类FooMain{
公共静态void main(字符串args[])引发异常{
GsonBuilder GsonBuilder=新的GsonBuilder();
registerTypeAdapter(X.class,新的XAdapter());
gsonBuilder.registerTypeAdapter(Map.class,新的MapAdapter());
Gson Gson=gsonBuilder.serializeNulls().create();
SomeType original=新的SomeType();
System.out.println(“原件为:“+原件”);
字符串foo=gson.toJson(原始,SomeType.class);
System.out.println(“JSON格式为:“+foo”);
SomeType=gson.fromJson(foo,SomeType.class);
System.out.println(“重构为:“+重构”);
}
}
类映射适配器实现JsonSerializer>{
@凌驾
公共JsonElement序列化(映射m,类型typeOfT,JsonSerializationContext){
JsonArray rv=新的JsonArray();
对于(对象k:m.keySet()){
JsonObject kv=新的JsonObject();
kv.add(“k”,context.serialize(k));
kv.addProperty(“ktype”,k.getClass().getName());
kv.add(“v”,context.serialize(m.get(k));
kv.addProperty(“vtype”,m.get(k.getClass().getName());
rv.增加(千伏);
}
返回rv;
}
@凌驾
公共映射反序列化(JsonElement _json,类型typeOfT,JsonDeserializationContext)引发JsonParseException{
JsonArray json=(JsonArray)\u json;
Map rv=新的HashMap();
for(int i=0;i
那么,在这种情况下该怎么办?@MarcusJuniusBrutus更改设计时,键(名称)必须是字符串。您需要实现一个自定义反序列化程序,该程序可以理解对象的字符串格式,并从中创建一个
X
对象。但是,当我尝试使用完整适配器(
JsonSerializer
JsonDeserializer
)以“释放”
toString()时,我可以使用自定义反序列化程序来实现这一点
方法出于其他目的,GSON继续使用
toString()
并忽略
Map
键类的自定义序列化程序。这也是你的理解吗?i、 例如,您必须使用
toString()
而不是使用自定义序列化程序?@MarcusJuniusBrutus我相信这取决于您在哪个级别应用自定义反序列化程序。我相信它应该出现在地图上。Gson默认使用字符串作为映射键中的JSON名称,这就是为什么您必须修改它,以便它在字符串f中序列化它
import java.util.*;
import com.google.gson.*;
import java.lang.reflect.Type;

import org.apache.commons.lang3.StringUtils;

class X {
    public int x;
    public X(int x) {
        this.x = x;
    }
    public String toString() {
        return String.format("boo ha ha %d", x);
    }
}

class SomeType {
    private Map <X,  String> map;
    public SomeType() {
        this.map = new HashMap<X, String>();
        map.put(new X(2), "b");
    }
    public String toString() {
        List<String> rv = new ArrayList<>();
        for (X x : map.keySet())
            rv.add(String.format("%s -> %s\n", x.toString(), map.get(x)));
        return StringUtils.join(rv, "\n");
    }
}

public class FooMain {

    public static void main(String args[]) throws Exception {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(X.class, new XAdapter());
        gsonBuilder.registerTypeAdapter(Map.class, new MapAdapter());
        Gson gson = gsonBuilder.serializeNulls().create();
        SomeType original = new SomeType();
        System.out.println("original is: "+original);
        String foo = gson.toJson(original, SomeType.class);
        System.out.println("JSON form is: "+foo);                     
        SomeType reconstructed = gson.fromJson(foo, SomeType.class);  
        System.out.println("reconstructed is: "+reconstructed);
    }
}


class MapAdapter implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {

    @Override
    public JsonElement serialize(Map<?, ?> m, Type typeOfT, JsonSerializationContext context) {
        JsonArray rv = new JsonArray();
        for (Object k : m.keySet()) {
            JsonObject kv = new JsonObject();
            kv.add        ("k"     , context.serialize(k));
            kv.addProperty("ktype" , k.getClass().getName());
            kv.add        ("v"     , context.serialize(m.get(k)));
            kv.addProperty("vtype" , m.get(k).getClass().getName());
            rv.add(kv);
        }
        return rv;
    }

    @Override
    public Map<?, ?> deserialize(JsonElement _json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonArray json = (JsonArray) _json;
        Map<Object, Object> rv = new HashMap<>();
        for (int i = 0 ; i < json.size() ; i++) {
            JsonObject o = (JsonObject) json.get(i);
            String ktype = o.getAsJsonPrimitive("ktype").getAsString();
            String vtype = o.getAsJsonPrimitive("vtype").getAsString();
            Class<?> kklass = null;
            Class<?> vklass = null;
            try {
                kklass = Class.forName(ktype);
                vklass = Class.forName(vtype);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new JsonParseException(e.getMessage());
            }
            Object k = context.deserialize( o.get("k"), kklass);
            Object v = context.deserialize( o.get("v"), vklass);
            rv.put(k, v);
        }
        return rv;
    }

}


class XAdapter implements JsonSerializer<X>, JsonDeserializer<X> {

    @Override
    public JsonElement serialize(X x, Type typeOfT, JsonSerializationContext context) {
        return context.serialize(x.x);
    }

    @Override
    public X deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        String s = json.getAsString();
        int x = Integer.valueOf(s);
        return new X(x);
    }
}