反序列化包含 java.lang.CharSequence 成员变量的类



我有一个简单的类name其中包含java.lang.CharSequence类型的变量

class Person {
public java.lang.CharSequence name;
}

当我尝试使用 GSON 库反序列化 JSON 字符串时

Person p;
Gson gson = new Gson();
String json = "{"name":"dinesh"}";
p = gson.fromJson(json, Person.class);
System.out.println(p);

它给了我以下错误:

java.lang.RuntimeException:无法为接口 java.lang.CharSequence 调用 no-args 构造函数。向 Gson 注册此类型的实例创建者可能会解决此问题。

我该如何解决这个问题?我无法将Person.name类型更改为String

正如评论中所建议的,

我为CharSequence创建了一个自定义适配器

class CharSequenceAdapter extends TypeAdapter<CharSequence> {
@Override
public void write(JsonWriter out, CharSequence value) throws IOException {

}
@Override
public CharSequence read(JsonReader in) throws IOException {
String s = new String();
in.beginObject();
while(in.hasNext()) {
s = in.nextString();
}
return s;
}

}

我的 GSON 构建器看起来像这样:

Person p;
GsonBuilder builder = new GsonBuilder().registerTypeAdapter(java.lang.CharSequence.class, new CharSequenceAdapter());
Gson gson = builder.create();
String json = "{"name":"dinesh"}";
p = gson.fromJson(json, Person.class);
System.out.println(p);

现在它给了我另一个错误:

预期BEGIN_OBJECT,但第 1 行第 10 列路径 $.name 处是字符串

我错过了什么?

我不认为这是重复的。所有其他问题都讨论将一个类或接口作为一个整体进行反序列化。我遇到一个将接口引用作为成员变量的类的问题。我无法从类似的答案中解决问题。

CharSequence是一个接口。

当 Gson 尝试将 json 字符串反序列化为对象时,它会"内省"对象(通过使用反射(并尝试解析字段类型。 然后,它尝试创建当时的字段。

开箱即用的Gson可以处理许多"广泛"的类型,如字符串,整数,布尔值等,但是当GSon不知道它的东西时(如本例中的CharSequence(,GSon会停止错误。

现在很明显,您应该"教"Gson理解此自定义类型。 为此,Gson 中有类型适配器。

在这里,您可以找到有关使用适配器的简短教程。 我不会在这里重写一个示例,但一般来说,你应该创建一个适配器,在 Gson 对象上注册它并调用你的代码。当 Gson 到达 CharSequence 字段时,它将找到此自定义适配器并调用它

如其他答案所述,Gson 没有用于CharSequence的内置适配器(请参阅相关的拉取请求(,因此无法反序列化它。

但是,您可以通过编写自定义TypeAdapter来解决此问题,例如:

class CharSequenceTypeAdapter extends TypeAdapter<CharSequence> {
@Override
public void write(JsonWriter out, CharSequence value) throws IOException {
if (value == null) {
out.nullValue();
} else {
// Assumes that value complies with CharSequence.toString() contract
out.value(value.toString());
}
}
@Override
public CharSequence read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
// Skip the JSON null
in.skipValue();
return null;
} else {
return in.nextString();
}
}
}

这假设您的CharSequence值被编码为 JSON 字符串值(例如"value"(,而不是作为 JSON 对象 ({ ... }(。对于序列化,它还假定您使用的值符合CharSequence.toString()协定。

然后,您必须使用用于创建Gson实例的GsonBuilder注册适配器:

Gson gson = new GsonBuilder()
.registerTypeAdapter(CharSequence.class, new CharSequenceTypeAdapter())
.create();

或者,如果您实际上总是使用String作为CharSequence值,那么您也可以将字段类型更改为String,以防这对代码的 API 没有任何负面影响。

你不需要in.beginObject();行。如果没有该行,代码可以正常工作。

最新更新