如何在Retrofit的POST请求中将JSONObject作为@Body参数使用
问题根因
你使用的Retrofit配置了GsonConverterFactory作为请求体转换器,Gson在序列化org.json.JSONObject类型的对象时,不会将它识别为特殊的JSON结构,而是按照普通Java对象的序列化规则,把它内部所有public的成员变量、静态常量全部序列化输出。你看到的nameValuePairs是JSONObject内部存储键值对的成员变量,NEGATIVE_ZERO是JSONObject内置的静态常量,所以才会出现在最终的请求体中。
解决方案
方案1:使用Gson的JsonObject类替代org.json.JSONObject
这是适配成本最低的方案,把你构造动态JSON的逻辑从org.json.JSONObject改成Gson库自带的com.google.gson.JsonObject,接口参数直接定义为@Body JsonObject jsonObject即可,Gson序列化自身的JsonObject类时会直接输出正确的JSON结构,不会生成多余字段。
示例代码:
// 构造动态JSON JsonObject jsonObject = new JsonObject(); JsonObject cfField = new JsonObject(); cfField.addProperty("pdf-name", "CAPTAIN BOBOYz"); cfField.addProperty("pdf-email", "boy@test.com"); // 剩余字段依次添加 jsonObject.add("cf-field", cfField); jsonObject.addProperty("lead_id", "273993"); // 直接传入接口调用即可 api.updateLead(token, jsonObject).enqueue(/* 你的回调逻辑 */);
方案2:将org.json.JSONObject转成字符串后用RequestBody传递
如果你不想修改现有构造org.json.JSONObject的逻辑,可以把构造好的JSONObject转成原始JSON字符串,再封装为RequestBody传入接口,直接跳过Gson对JSONObject的序列化流程:
- 修改Retrofit接口定义:
@Headers(PARAM_HEADER_JSON) @POST(HttpConstants.LEAD_EDIT) Call<LeadDetailsResult> updateLead(@Header(PARAM_TOKEN) String token, @Body RequestBody body);
- 调用接口前做如下转换:
// 你原来构造好的org.json.JSONObject对象 JSONObject yourJson = ...; RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), yourJson.toString()); // 传入body调用接口即可 api.updateLead(token, body).enqueue(/* 你的回调逻辑 */);
方案3:自定义Gson TypeAdapter适配org.json.JSONObject
如果项目里大量使用org.json.JSONObject作为请求体,不想逐个修改调用逻辑,可以给Gson添加自定义的TypeAdapter,专门处理org.json.JSONObject的序列化逻辑:
public class JSONObjectTypeAdapter extends TypeAdapter<JSONObject> { @Override public void write(JsonWriter out, JSONObject value) throws IOException { if (value == null) { out.nullValue(); return; } out.jsonValue(value.toString()); } @Override public JSONObject read(JsonReader in) throws IOException { try { return new JSONObject(JsonParser.parseReader(in).getAsString()); } catch (JSONException e) { throw new IOException(e); } } }
然后在构造Gson实例时注册这个适配器,再把自定义的Gson实例传给GsonConverterFactory构造你的Retrofit实例即可,原有代码不需要做任何修改就能正常输出正确的JSON结构。
内容的提问来源于stack exchange,提问作者nerdy kid

