使用Gson.toJson序列化嵌套org.json.JSONObject时被归入map键问题
解决Gson序列化org.json.JSONObject时的嵌套问题
这个问题我之前也碰到过,核心原因是Gson默认没有内置对org.json.JSONObject的序列化支持,它会把JSONObject当成普通的Map<String, Object>来处理,所以最终序列化出来的结果才会把JSONObject的内容嵌套到map相关的键下。要解决这个,我们需要给Gson添加一个自定义的TypeAdapter,明确告诉它该如何正确处理org.json.JSONObject。
步骤1:编写自定义TypeAdapter
我们需要实现com.google.gson.TypeAdapter<org.json.JSONObject>,重写序列化和反序列化的逻辑:
import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import org.json.JSONObject; import java.io.IOException; public class JSONObjectTypeAdapter extends TypeAdapter<JSONObject> { @Override public void write(JsonWriter out, JSONObject value) throws IOException { // 直接将JSONObject的字符串写入,Gson会自动解析成正确的JSON结构 out.jsonValue(value.toString()); } @Override public JSONObject read(JsonReader in) throws IOException { // 反序列化时,先读取成JsonElement再转成JSONObject com.google.gson.JsonElement element = new com.google.gson.JsonParser().parse(in); return new JSONObject(element.toString()); } }
步骤2:注册适配器到GsonBuilder
在创建Gson实例的时候,把上面的适配器注册进去:
private static final Gson gson = new GsonBuilder() .disableHtmlEscaping() .registerTypeAdapter(JSONObject.class, new JSONObjectTypeAdapter()) .create();
完整示例代码
假设你的User类里有一个JSONObject类型的字段,比如:
import org.json.JSONObject; public class User { private String name; private int age; private JSONObject extraInfo; // 要序列化的JSONObject字段 // 构造器、getter、setter省略 public User(String name, int age, JSONObject extraInfo) { this.name = name; this.age = age; this.extraInfo = extraInfo; } }
然后修改你的something方法,用注册了适配器的Gson来序列化:
public class New { private static final Gson gson = new GsonBuilder() .disableHtmlEscaping() .registerTypeAdapter(JSONObject.class, new JSONObjectTypeAdapter()) .create(); public static void something(User user) throws Exception { // 直接用自定义的Gson实例序列化User对象 String jsonResult = gson.toJson(user); System.out.println(jsonResult); } public static void main(String[] args) throws Exception { JSONObject extra = new JSONObject(); extra.put("hobby", "reading"); extra.put("address", "Beijing"); User user = new User("Alice", 25, extra); something(user); } }
效果验证
运行上面的代码,输出的JSON会是这样的:
{"name":"Alice","age":25,"extraInfo":{"hobby":"reading","address":"Beijing"}}
可以看到extraInfo里的内容直接展开了,不会再嵌套到map相关的键下。
额外说明
如果你是先通过Jackson的ObjectMapper把User转成JSON字符串,再转成JSONObject,其实可以跳过这一步,直接用Gson来处理User对象——毕竟混用多个JSON库容易出现兼容性问题,尽量保持序列化/反序列化用同一个库会更稳妥。
内容的提问来源于stack exchange,提问作者Awesumbanana
相关产品推荐
相关产品推荐

