GSON基于值从序列化中排除某些字段

10

我正在使用GSON进行序列化,但我发现无法根据字段的值通过Gson提供的ExclusionStrategy类来排除某些字段的序列化。因为它只支持基于顶级类或字段属性的排除,而字段属性不包括该字段的值。那我应该怎么办呢?

3个回答

22

通过为相关类创建自定义序列化器来实现此目的。在允许Gson以默认方式创建JSON对象后,根据其值删除要排除的属性。

public class SerializerForMyClass implements JsonSerializer<MyClass> {  

    @Override
    public JsonElement serialize(MyClass obj, Type type, JsonSerializationContext jsc) {
        Gson gson = new Gson();
        JsonObject jObj = (JsonObject)gson.toJsonTree(obj);   
        if(obj.getMyProperty()==0){
            jObj.remove("myProperty");
        }
        return jObj;
    }
}

在应用程序中,为这个类进行序列化的 Gson 对象中注册新的序列化器。

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MyClass.class, new SerializerForMyClass());
Gson gson=gsonBuilder.create();
gson.toJson(myObjectOfTypeMyClass);

1
在我的情况下,我想要删除所有的 false 布尔值(整个元素),但是使用这种方法不可能实现。如果您知道一种有效的方法来做到这一点,我很乐意学习。最终,我拦截了所有超级对象并手动删除了每个 false 布尔属性。 - Steven
请注意 JsonSerializer 的文档中写道:新应用程序应该优先考虑TypeAdapter,其流API比此接口的树API更有效 - user905686

1
这是我如何使用类型适配器来避免序列化布尔值为 false。它避免了创建额外的 Gson 实例,并且不依赖于特定的字段名称。
class MyClassTypeAdapter: JsonSerializer<MyClass>{
   override fun serialize(myObject: MyClass, type: Type, context: JsonSerializationContext): JsonElement {
      val jsonElement = context.serialize(myObject)

      jsonElement.asJsonObject.entrySet().removeAll { it.value is JsonPrimitive && (it.value as JsonPrimitive).isBoolean && !it.value.asBoolean }

      return jsonElement
   }
}

0

这是我写的一个类的更深入的例子,用于删除所有错误的布尔值和所有"false"字符串。它被匆忙拼凑在一起,但似乎工作得不错。如果你发现有任何 bug,请让我知道。

public class RemoveFalseJsonSerializer implements JsonSerializer<Object> {

//~ Methods --------------------------------------------------------------------------------------------------------

/**
 * serialize
 *
 * @param object in value
 * @param type in value
 * @param jsonSerializationContext in value
 *
 * @return out value
 */
@Override
public JsonElement serialize(Object object, Type type, JsonSerializationContext jsonSerializationContext) {
    Gson gson = new Gson();
    JsonElement jsonElement = gson.toJsonTree(object);
    trimJson(jsonElement);
    return jsonElement;
}

/**
 * We've finally made it to a primitive of some sort.  Should we trim it?
 *
 * @param jsonElement in value
 *
 * @return out value
 */
private boolean shouldTrimElement(JsonElement jsonElement) {
    return jsonElement == null || jsonElement.isJsonNull()
            || (jsonElement.isJsonPrimitive()
                && ((jsonElement.getAsJsonPrimitive().isBoolean() && !jsonElement.getAsBoolean()) // trim false
                    || (jsonElement.getAsJsonPrimitive().isString() // also trim the string "false"
                        && "false".equalsIgnoreCase(jsonElement.getAsString()))));
}

/**
 * trimJson
 *
 * @param jsonElement in value
 */
private void trimJson(JsonElement jsonElement) {
    if (jsonElement == null || jsonElement.isJsonNull() || jsonElement.isJsonPrimitive()) {
        return;
    }

    if (jsonElement.isJsonObject()) {
        List<String> toRemove = new ArrayList<>();
        JsonObject asJsonObject = jsonElement.getAsJsonObject();
        for (Map.Entry<String, JsonElement> jsonElementEntry : asJsonObject.entrySet()) {
            if (jsonElementEntry.getValue().isJsonObject() || jsonElementEntry.getValue().isJsonArray()) {
                trimJson(jsonElementEntry.getValue());
            } else if (shouldTrimElement(jsonElementEntry.getValue())) {
                toRemove.add(jsonElementEntry.getKey());
            }
        }
        if (CollectionUtils.isNotEmpty(toRemove)) {
            for (String remove : toRemove) {
                asJsonObject.remove(remove);
            }
        }
    } else if (jsonElement.isJsonArray()) {
        JsonArray asJsonArray = jsonElement.getAsJsonArray();
        for (JsonElement element : asJsonArray) {
            trimJson(element);
        }
    }
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接