使用 GSON 不解析字段,只保留 json 原始字符串

Posted

技术标签:

【中文标题】使用 GSON 不解析字段,只保留 json 原始字符串【英文标题】:Using GSON do not parse a field, only keep it with the json raw string 【发布时间】:2017-06-29 17:11:53 【问题描述】:

在 Java 中使用 GSON 是否有任何注释,我可以在其中指示一个字段,即使它是一个对象,它也应该将其保留为原始字符串。 ?

或者实现这一目标的最简单方法是什么?

//This is the original
    @SerializedName("perro")
    public Perro perro

//This is what I want to achieve 
    @SerializedName("perro")
    public String perro

So the result should be 
perro = ""Users":["Name":"firulais","Raza":"beagle","Name":"Spike","Value":"Terrier"]"

【问题讨论】:

我不明白。 Java String 将被序列化为 JSON 字符串。你能举个例子说明一下吗? 所以说我有一个 Java 类调用 Animal.java 有很多字段其中一个字段是调用 Perro 它是一个对象,所以如果我有一个 String 响应它实际上是一个 JSON ,那么如果我做了类似 Animal animal = gson.fromJson(response,Animal.class) 的事情,然后我希望 Perro 字段作为 json 原始字符串保存,而不是将其解析为 Perro 对象。 请使用示例 JSON 有效负载编辑您的问题。如果您的字段是Object 类型并且它实际上是JSON 中的JSON 字符串,我相信Gson 将无法解析。如果是Object,Gson 需要一个 JSON 对象。 所以对象类型的字段我希望它是字符串类型,不解析该字段,只保留该字段特定的原始 Json 字符串 【参考方案1】:

我发现这个工作的唯一方法是使用

public JsonElement perro;

【讨论】:

谢谢,这正是我想要的! 虽然这行得通,但它使用了大量内存,因为 JsonElement 将整个 json 结构作为树保存在内存中。【参考方案2】:

根据@mrsegev 的回答,这里有一个更简单的版本(在 Kotlin 中),适用于任意对象:

class RawJsonAdapter: TypeAdapter<String>() 
    override fun write(out: JsonWriter?, value: String?) 
        out?.jsonValue(value)
    
    override fun read(reader: JsonReader?): String 
        return JsonParser().parse(reader).toString()
    

这利用了在https://github.com/google/gson/pull/667 中添加的JsonWriter#jsonValue()

用法:

@JsonAdapter(RawJsonAdapter::class)
val fieldName: String? = null

【讨论】:

github.com/google/gson/issues/1368#issuecomment-417821473有更新版本 对于 moshi 中的等价物,请参阅 github.com/square/moshi/issues/675#issuecomment-842732058【参考方案3】:

基本上,你需要创建一个自定义的gsonTypeAdapter类,并自己编写从Object到String的转换登录。

然后注释指示使用什么 TypeAdapter 的字段,以便使用 gson 读取/写入它。

此博文中的更多详细信息:Gson TypeAdapter Example

示例:将类对象转换为原始 JSON 字符串

public class StringTypeAdapter extends TypeAdapter<String> 

    @Override
    public void write(JsonWriter out, String value) throws IOException 
        try 
            JSONObject jsonObject = new JSONObject(value);
            out.beginObject();
            Iterator<String> iterator = jsonObject.keys();
            while (iterator.hasNext()) 
                String key = iterator.next();
                String keyValue = jsonObject.getString(key);
                out.name(key).value(keyValue);
            
            out.endObject();
         catch (JSONException e) 
            e.printStackTrace();
        
    

    @Override
    public String read(JsonReader in) throws IOException 
        in.beginObject();
        JSONObject jsonObject = new JSONObject();
        while (in.hasNext()) 
            final String name = in.nextName();
            final String value = in.nextString();
            try 
                jsonObject.put(name, value);
             catch (JSONException e) 
                e.printStackTrace();
            
        
        in.endObject();
        return jsonObject.toString();
    

使用 TypeAdapter:

@JsonAdapter(StringTypeAdapter.class)
private String someClass; // Lazy parsing this json

【讨论】:

我尝试使用 TypeAdapter 但如何将 JsonReader 转换为原始字符串? 用一个示例更新了我的答案,将类对象解析为原始 JSON 字符串。 这个不起作用,在读取是否有 JSONObject 作为字符串时,它会出现异常 仅供参考,TypeAdapter 的 write() 方法可以使用 jsonValue() 直接发出原始 json。见github.com/google/gson/pull/667【参考方案4】:

你应该可以使用public JsonObject perro;

然后您可以调用gson.toJson(perro) 来获取String 值。

【讨论】:

我尝试使用@SerializedName("perro") public JsonObject perro 但不起作用 @KenenisaBekele 你能包含你正在转换的完整 json 字符串吗...我在一些地方使用我在回答中提到的方法,其中 json 有效负载中的字段包含另一个 json 字符串。 ...但也许你所拥有的并不完全是这种情况。 没有理由再次涉及Gson 实例。只需使用perro.toString() 即可获得String 表示。 @KenenisaBekele 为什么这个答案被否决了。这是一个没有自定义类型适配器的好解决方案。 不起作用 预期为 com.google.gson.JsonObject 但为 com.google.gson.JsonPrimitive

以上是关于使用 GSON 不解析字段,只保留 json 原始字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 GSON 解析动态 JSON 字段?

在用Gson解析对象的时候,json数据中没有的字段,会赋初值。

使用google的Gson库和alibaba的Fastjson库解析json数据的区别

Kotlin如何使用GSON解析动态JSON字段?

当列表的各个项目使用Retrofit和Gson的格式不同时,如何解析json列表?

android gson可以只解析json中想要的属性吗