为何GSON解析期望BEGIN_OBJECT,但我已将变量定义为STRING?
问题排查与解决
错误原因
Gson原生不支持Java Optional<T> 类型的反序列化逻辑。你的Pending类中date字段定义为Optional<String>,Gson会默认把Optional当作一个对象来解析(期望JSON结构是{}),但实际JSON里的date是字符串类型(比如"2023-11-24"),这就导致了Expected BEGIN_OBJECT but was STRING的类型不匹配错误。
解决方案
方案1:自定义Optional类型的TypeAdapter
编写一个适配Optional的TypeAdapter,让Gson能正确将字符串(或null)转换为Optional<String>:
public class OptionalTypeAdapter extends TypeAdapter<Optional<String>> { @Override public void write(JsonWriter out, Optional<String> value) throws IOException { if (value.isPresent()) { out.value(value.get()); } else { out.nullValue(); } } @Override public Optional<String> read(JsonReader in) throws IOException { JsonToken token = in.peek(); if (token == JsonToken.NULL) { in.nextNull(); return Optional.empty(); } else if (token == JsonToken.STRING) { String str = in.nextString(); return Optional.ofNullable(str.isEmpty() ? null : str); } else { throw new JsonSyntaxException("Expected STRING or NULL but was " + token); } } }
然后创建Gson实例时注册这个适配器:
Gson gson = new GsonBuilder() .registerTypeAdapter(new TypeToken<Optional<String>>(){}.getType(), new OptionalTypeAdapter()) .create(); // 之后用这个gson实例反序列化 Output output = gson.fromJson(bodyString, Output.class);
方案2:替换Optional为普通String(更简单)
如果不需要用Optional来处理空值,可以直接把Pending类中的date字段改成普通String,用null表示空:
@Builder class Pending { @SerializedName("req_id") public final String reqId; @SerializedName("status") public final String status; @SerializedName("date") @Builder.Default public final String date = null; }
这样Gson就能直接将JSON中的字符串(或缺失的字段)映射为String类型,不会报错。
方案3:使用Gson的Optional扩展(需引入依赖)
如果你的项目已经依赖了Guava,可以使用Guava提供的Gson支持,添加guava-gson依赖后,Gson可以自动处理Optional类型。不过这种方式需要额外引入依赖,适合已有Guava的项目。
内容的提问来源于stack exchange,提问作者topinfx
相关产品推荐
相关产品推荐

