我想序列化特定字段或类的空值.
在GSON中,该选项serializeNulls()适用于整个JSON.
例:
class MainClass {
public String id;
public String name;
public Test test;
}
class Test {
public String name;
public String value;
}
MainClass mainClass = new MainClass();
mainClass.id = "101"
// mainClass has no name.
Test test = new Test();
test.name = "testName";
test.value = null;
mainClass.test = test;
Run Code Online (Sandbox Code Playgroud)
使用GSON创建JSON:
GsonBuilder builder = new GsonBuilder().serializeNulls();
Gson gson = builder.create();
System.out.println(gson.toJson(mainClass));
Run Code Online (Sandbox Code Playgroud)
当前输出:
{
"id": "101",
"name": null,
"test": {
"name": "testName",
"value": null
}
}
Run Code Online (Sandbox Code Playgroud)
期望的输出:
{
"id": "101",
"test": {
"name": "testName",
"value": null
}
}
Run Code Online (Sandbox Code Playgroud)
如何实现所需的输出?
首选解决方案具有以下属性:
Jor*_*ris 12
我有一个类似于 Aleksey 的解决方案,但它可以应用于任何类中的一个或多个字段(Kotlin 中的示例):
为应序列化为 null 的字段创建一个新注释:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class SerializeNull
Run Code Online (Sandbox Code Playgroud)
创建一个TypeAdapterFactory检查类是否具有使用此批注注释的字段,null并JsonTree在编写对象时删除使用该批注和未使用该批注进行批注的字段:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class SerializeNull
Run Code Online (Sandbox Code Playgroud)
向您的 Gson 实例注册适配器:
val builder = GsonBuilder().registerTypeAdapterFactory(SerializableAsNullConverter())
Run Code Online (Sandbox Code Playgroud)
并注释您希望可以为空的字段:
class MyClass(val id: String?, @SerializeNull val name: String?)
Run Code Online (Sandbox Code Playgroud)
序列化结果:
val myClass = MyClass(null, null)
val gson = builder.create()
val json = gson.toJson(myClass)
Run Code Online (Sandbox Code Playgroud)
json:
{
"name": null
}
Run Code Online (Sandbox Code Playgroud)
我有接口来检查对象何时应该被序列化为空:
public interface JsonNullable {
boolean isJsonNull();
}
Run Code Online (Sandbox Code Playgroud)
以及对应的TypeAdapter(支持只写)
public class JsonNullableAdapter extends TypeAdapter<JsonNullable> {
final TypeAdapter<JsonElement> elementAdapter = new Gson().getAdapter(JsonElement.class);
final TypeAdapter<Object> objectAdapter = new Gson().getAdapter(Object.class);
@Override
public void write(JsonWriter out, JsonNullable value) throws IOException {
if (value == null || value.isJsonNull()) {
//if the writer was not allowed to write null values
//do it only for this field
if (!out.getSerializeNulls()) {
out.setSerializeNulls(true);
out.nullValue();
out.setSerializeNulls(false);
} else {
out.nullValue();
}
} else {
JsonElement tree = objectAdapter.toJsonTree(value);
elementAdapter.write(out, tree);
}
}
@Override
public JsonNullable read(JsonReader in) throws IOException {
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
使用方法如下:
public class Foo implements JsonNullable {
@Override
public boolean isJsonNull() {
// You decide
}
}
Run Code Online (Sandbox Code Playgroud)
在 Foo 值应序列化为 null 的类中。注意 foo 值本身不能为空,否则自定义适配器注解将被忽略。
public class Bar {
@JsonAdapter(JsonNullableAdapter.class)
public Foo foo = new Foo();
}
Run Code Online (Sandbox Code Playgroud)
对于那些正在寻找@Joris 优秀答案的 Java 版本的人,下面的代码应该可以解决问题。它在很大程度上只是 Kotlin 的翻译,对如何获取属性的序列化名称进行了微小的改进,以确保它在序列化名称与属性名称不同时始终有效(请参阅原始答案的注释)。
这是TypeAdapterFactory实现:
public class NullableAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Field[] declaredFields = type.getRawType().getDeclaredFields();
List<String> nullableFieldNames = new ArrayList<>();
List<String> nonNullableFieldNames = new ArrayList<>();
for (Field declaredField : declaredFields) {
if (declaredField.isAnnotationPresent(JsonNullable.class)) {
if (declaredField.getAnnotation(SerializedName.class) != null) {
nullableFieldNames.add(declaredField.getAnnotation(SerializedName.class).value());
} else {
nullableFieldNames.add(declaredField.getName());
}
} else {
if (declaredField.getAnnotation(SerializedName.class) != null) {
nonNullableFieldNames.add(declaredField.getAnnotation(SerializedName.class).value());
} else {
nonNullableFieldNames.add(declaredField.getName());
}
}
}
if (nullableFieldNames.size() == 0) {
return null;
}
TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(NullableAdapterFactory.this, type);
TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
JsonObject jsonObject = delegateAdapter.toJsonTree(value).getAsJsonObject();
for (String name: nonNullableFieldNames) {
if (jsonObject.has(name) && jsonObject.get(name) instanceof JsonNull) {
jsonObject.remove(name);
}
}
out.setSerializeNulls(true);
elementAdapter.write(out, jsonObject);
}
@Override
public T read(JsonReader in) throws IOException {
return delegateAdapter.read(in);
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
这是@JsonNullable标记目标属性的注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonNullable {
}
Run Code Online (Sandbox Code Playgroud)
我将它实现为@JsonAdapter(NullableAdapterFactory.class)对象类上的注释,而不是将其注册为实例TypeAdapterFactory上的a GsonBuilder,所以我的对象类看起来有点像这样:
@JsonAdapter(NullableAdapterFactory.class)
public class Person {
public String firstName;
public String lastName;
@JsonNullable
public String someNullableInfo;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果愿意,另一种方法应该与此代码同样有效。