如何将缓存的 json 字符串与 gson 一起使用?

Posted

技术标签:

【中文标题】如何将缓存的 json 字符串与 gson 一起使用?【英文标题】:How to use a cached json string with gson? 【发布时间】:2014-01-30 17:31:54 【问题描述】:

我有一个保存缓存的 json 字符串的类:

class Foo 
    private transient String cachedJson; // value = [ "john", "mary" ]
    private List<String> names;

当我使用 gson 序列化 Foo 类的实例时,有没有一种方法可以让我拥有一个自定义序列化程序,只需为“名称”字段写入缓存的字符串,而不是让序列化程序重新序列化所有内容?比如:

public class CustomParserFoo implements 
JsonSerializer<Foo> 

    @Override
    public JsonElement serialize(Foo src, 
                                 Type typeOfSrc, 
                                 JsonSerializationContext context) 
    
        JsonObject element = new JsonObject();
        if (src.cachedJson != null) 
            // cached value present, use it.
            element.addProperty("names", src.cachedJson); 
         else 
            // have to really serialize it.
            element.addProperty("names", ...); 
        
        return element;
    

上面的问题是gson会尝试转义你提供的字符串(它已经被json转义了)。

用例类似于拥有一个非常大的对象,并且只有一个字段可能会更改,并且您必须经常对其进行序列化 - 所以不必重新序列化整个对象,只需重新序列化属性就好了已经改变了。

谢谢

【问题讨论】:

【参考方案1】:

当使用 Gson 进行序列化时,您正在创建一个解析树,而 Gson 负责编写;不幸的是,它不提供告诉它通过您的类中的字段的功能,因为它已经是 JSON。

你必须这样做是使用com.google.gson.JsonParser 类给你一个JsonElement

JsonElement cachedArray = new JsonParser().parse(src.cachedJson);
element.addProperty("names", cachedArray);

因为这意味着您正在反序列化缓存的 JSON,以便 gson 稍后可以写出整个解析树,所以将您的 JSON 缓存为 JsonArray 可能更有意义。

编辑添加: 值得一提的是,Jackson JSON 解析器确实提供了这种序列化功能。您可以使用@JsonRawValue 注释字段或方法,然后它会通过它。

【讨论】:

但是这个解决方案确实将String 解析为一个对象,然后将其写入流中。 @SotiriosDelimanolis 非常正确。但真的没有办法解决这个问题。在序列化时使用 Gson,您正在使用解析树,而 gson 负责编写。 OP 缓存 JsonArray 可能更有意义 好吧,是的,我想他们需要通过类似于杰克逊所做的事情进行特殊处理。谢谢!【参考方案2】:

在我们的服务中,我们为每个请求花费 200 毫秒只是对缓存对象进行 gson 序列化。我们更改了架构以缓存 json 字符串并直接返回它们。

您必须重新打包 gson 库并创建自己的:

package repackaged.com.google.gson;

public class JsonElementCache extends JsonElement 
    String cache;
    public JsonElementCache(String cache) 
        this.cache = cache;
    

    public String getCache() 
        return cache;
    

    @Override
    JsonElement deepCopy() 
        return new JsonElementCache(this.cache);
    

这将允许您在 TypeAdapters 类中更改这一行:

 @Override public void write(JsonWriter out, JsonElement value) throws IOException 
      if (value == null || value.isJsonNull()) 
      if (value instanceof JsonElementCache) 
        out.writeCached(((JsonElementCache) value).getCache());
      
      else if (value == null || value.isJsonNull()) 

JsonWriter.class 中也是这样:

public void writeCached(String str) 
    try 
        writeDeferredName();
        beforeValue(false);
        out.write(str);
    
    catch (Exception e) 
        e.printStackTrace();
    

希望这是有道理的。

【讨论】:

以上是关于如何将缓存的 json 字符串与 gson 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

java中如何将对象转成json格式字符串

Java Gson 实现 Json 数据的生成与解析

Gson 无法解析 Kotlin 中的字符串 json 格式数据

一起Talk Android吧(第三百五十三回:Gson库解析JSON数组一)

使用 Gitlab 仪表板 - 如何将 grafonnet 与 jsonnet 一起使用以生成我可以与 Grafana 一起使用的 json 文件

最佳实践 - Json 解析中的字符串与 InputStream(使用 gson)