我想序列化特定字段或类的空值。
在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;
使用GSON创建JSON:
GsonBuilder builder = new GsonBuilder().serializeNulls();
Gson gson = builder.create();
System.out.println(gson.toJson(mainClass));
电流输出:
{
"id": "101",
"name": null,
"test": {
"name": "testName",
"value": null
}
}
期望输出:
{
"id": "101",
"test": {
"name": "testName",
"value": null
}
}
如何达到预期的输出?
首选解决方案应具有以下特性:
对于那些寻找@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);
}
};
}
}
这是标记目标属性的@JsonNullable
注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonNullable {
}
我将其实现为对象类上的@JsonAdapter(NullableAdapterFactory.class)
注释,而不是将其注册为GsonBuilder
实例上的TypeAdapterFactory
,因此我的对象类看起来有点像这样:
@JsonAdapter(NullableAdapterFactory.class)
public class Person {
public String firstName;
public String lastName;
@JsonNullable
public String someNullableInfo;
}
然而,如果愿意的话,另一种方法也应该适用于此代码。
我有接口来检查对象何时应序列化为空:
public interface JsonNullable {
boolean isJsonNull();
}
以及相应的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;
}
}
使用方法如下:
public class Foo implements JsonNullable {
@Override
public boolean isJsonNull() {
// You decide
}
}
在类中,Foo值应序列化为null。请注意,foo值本身不能为null,否则将忽略自定义适配器注释。
public class Bar {
@JsonAdapter(JsonNullableAdapter.class)
public Foo foo = new Foo();
}
我有一个类似于Aleksey的解决方案,但可以应用于任何类中的一个或多个字段(例如Kotlin):
为应序列化为null的字段创建新注释:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class SerializeNull
创建一个TypeAdapterFactory
,检查一个类是否有用此注释注释的字段,并在编写对象时从JsonTree
中删除没有用注释注释的null
字段:
kotlin prettyprint-override">class SerializableAsNullConverter : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
fun Field.serializedName() = declaredAnnotations
.filterIsInstance<SerializedName>()
.firstOrNull()?.value ?: name
val declaredFields = type.rawType.declaredFields
val nullableFieldNames = declaredFields
.filter { it.declaredAnnotations.filterIsInstance<SerializeNull>().isNotEmpty() }
.map { it.serializedName() }
val nonNullableFields = declaredFields.map { it.serializedName() } - nullableFieldNames
return if (nullableFieldNames.isEmpty()) {
null
} else object : TypeAdapter<T>() {
private val delegateAdapter = gson.getDelegateAdapter(this@SerializableAsNullConverter, type)
private val elementAdapter = gson.getAdapter(JsonElement::class.java)
override fun write(writer: JsonWriter, value: T?) {
val jsonObject = delegateAdapter.toJsonTree(value).asJsonObject
nonNullableFields
.filter { jsonObject.get(it) is JsonNull }
.forEach { jsonObject.remove(it) }
val originalSerializeNulls = writer.serializeNulls
writer.serializeNulls = true
elementAdapter.write(writer, jsonObject)
writer.serializeNulls = originalSerializeNulls
}
override fun read(reader: JsonReader): T {
return delegateAdapter.read(reader)
}
}
}
}
向Gson实例注册适配器:
val builder = GsonBuilder().registerTypeAdapterFactory(SerializableAsNullConverter())
并注释您希望为空的字段:
class MyClass(val id: String?, @SerializeNull val name: String?)
序列化结果:
val myClass = MyClass(null, null)
val gson = builder.create()
val json = gson.toJson(myClass)
json:
{
"name": null
}
问题内容: 我想基于字段值将json对象反序列化为特定类型的对象(使用Gson库),例如: 因此,字段将具有不同(但已知)的值。基于该值,我需要将该json对象反序列化为适当的模型对象,例如:Type1Model,Type2Model等。我知道我可以轻松地在反序列化之前通过将其转换为,迭代并确定应该反序列化为哪种类型来完成此操作。 。但是我认为这是丑陋的方法,我正在寻找更好的方法。有什么建议? 问
首先,我想说这是一个大学项目。 我有三节课<代码>订单抽象类和从订单继承的和类。 我使用Gson序列化/反序列化子类,但我遇到了一点问题。订单类有一个字段,gson使用该字段来确定订单类型,DineIn或Delivery。 序列化工作得很好。问题是,每当我尝试反序列化时,类型字段值都不会读取,并且总是设置为null,即使它存在于JSON文件中。当有很多字段时,就会发生这种情况,因为当我尝试在较小的
问题内容: 我有以下JSON字符串: 我需要将值存储在单独的字符串中。 这是我到目前为止所拥有的,但这只是为我提供了整个JSON字符串,而不是特定的imgurl字段。 是JSON字符串。这是我的数据类: 问题答案: 解析这种简单的结构时,不需要专用的类。 解决方案1: 要使用gson从字符串中获取imgurURL,可以执行以下操作: 这使用原始解析到JsonObject中。 解决方案2: 另外,您
这是我目前所拥有的,但这只给了我整个JSON字符串,而不是特定的imgurl字段。 是JSON字符串。下面是我的数据类:
是否有方法序列化类的瞬态字段?文档中提到默认情况下不支持它,但是否有办法打开它? 非常感谢
我试图使用Gson自定义序列化将以下类序列化为Json。