有没有一种通用的方法告诉Gson不要写空字符串?
我非常不喜欢实现一个TypeAdapter,它可以像这里的答案所暗示的那样处理每个字段。
感谢@Lyuboyr的回答,但我找到了一个更适合我们用例的解决方案:
如果我们将所有空字符串和对象设置为空,序列化后剩下的JSON只包含具有实际数据的节点:
/**
* convert object to json
*/
public String toJson(Object obj) {
// Convert emtpy string and objects to null so we don't serialze them
setEmtpyStringsAndObjectsToNull(obj);
return gson.toJson(obj);
}
/**
* Sets all empty strings and objects (all fields null) including sets to null.
*
* @param obj any object
*/
public void setEmtpyStringsAndObjectsToNull(Object obj) {
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object fieldObj = field.get(obj);
if (fieldObj != null) {
Class fieldType = field.getType();
if (fieldType.isAssignableFrom(String.class)) {
if(fieldObj.equals("")) {
field.set(obj, null);
}
} else if (fieldType.isAssignableFrom(Set.class)) {
for (Object item : (Set) fieldObj) {
setEmtpyStringsAndObjectsToNull(item);
}
boolean setFielToNull = true;
for (Object item : (Set) field.get(obj)) {
if(item != null) {
setFielToNull = false;
break;
}
}
if(setFielToNull) {
setFieldToNull(obj, field);
}
} else if (!isPrimitiveOrWrapper(fieldType)) {
setEmtpyStringsAndObjectsToNull(fieldObj);
boolean setFielToNull = true;
for (Field f : fieldObj.getClass().getDeclaredFields()) {
f.setAccessible(true);
if(f.get(fieldObj) != null) {
setFielToNull = false;
break;
}
}
if(setFielToNull) {
setFieldToNull(obj, field);
}
}
}
} catch (IllegalAccessException e) {
System.err.println("Error while setting empty string or object to null: " + e.getMessage());
}
}
}
private void setFieldToNull(Object obj, Field field) throws IllegalAccessException {
if(!Modifier.isFinal(field.getModifiers())) {
field.set(obj, null);
}
}
private boolean isPrimitiveOrWrapper(Class fieldType) {
return fieldType.isPrimitive()
|| fieldType.isAssignableFrom(Integer.class)
|| fieldType.isAssignableFrom(Boolean.class)
|| fieldType.isAssignableFrom(Byte.class)
|| fieldType.isAssignableFrom(Character.class)
|| fieldType.isAssignableFrom(Float.class)
|| fieldType.isAssignableFrom(Long.class)
|| fieldType.isAssignableFrom(Double.class)
|| fieldType.isAssignableFrom(Short.class);
}
运行相当快的性能。如果您有很多空字段,这可以在序列化和发送/写入数据库时节省时间(和空间)。
算是吧。据我所知,Gson不会让你控制太多的对象字段,唯一的控制我知道你可以拥有它@JsonAdapter
。例如,
import com.google.gson.annotations.JsonAdapter;
final class Pack {
@JsonAdapter(EmptyStringTypeAdapter.class)
final String foo;
@JsonAdapter(EmptyStringTypeAdapter.class)
final String bar;
private Pack(final String foo, final String bar) {
this.foo = foo;
this.bar = bar;
}
static Pack of(final String foo, final String bar) {
return new Pack(foo, bar);
}
@Override
public String toString() {
return foo + " " + bar;
}
}
尽管对某些人来说可能看起来很乏味,但它可以让你完全控制数据传输对象,让你可以选择如何处理这个或那个字符串。示例类型适配器可能如下所示:
final class EmptyStringTypeAdapter
extends TypeAdapter<String> {
private EmptyStringTypeAdapter() {
}
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter jsonWriter, @Nullable final String s)
throws IOException {
if ( s == null || s.isEmpty() ) {
jsonWriter.nullValue();
} else {
jsonWriter.value(s);
}
}
@Override
@Nonnull
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
public String read(final JsonReader jsonReader)
throws IOException {
final JsonToken token = jsonReader.peek();
switch ( token ) {
case NULL:
return "";
case STRING:
return jsonReader.nextString();
default:
throw new IllegalStateException("Unexpected token: " + token);
}
}
}
这里需要注意的一点是,它无法从空字符串中恢复空字符串(不幸的是,您在这里遇到了不可逆的转换),所以您可能还想看看https://github.com/google/html" target="_blank">gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java要还原@JsonAdapter(EmptyStringTypeAdapter.class)
,请在读取时还原带注释的字段。示例测试:
private static final Gson gson = new Gson();
private static final Type listOfStringType = new TypeToken<List<String>>() {
}.getType();
public static void main(final String... args) {
// Single elements
ImmutableList.of(Pack.of("", ""), Pack.of("foo", ""), Pack.of("", "bar"), Pack.of("foo", "bar"))
.stream()
.peek(pack -> System.out.println("Pack before: " + pack))
.map(gson::toJson)
.peek(json -> System.out.println("JSON: " + json))
.map(json -> gson.fromJson(json, Pack.class))
.peek(pack -> System.out.println("Pack after: " + pack))
.forEach(pack -> System.out.println());
// Multiple elements
final List<String> stringsBefore = ImmutableList.of("", "foo", "bar");
System.out.println(stringsBefore);
final String stringsJson = gson.toJson(stringsBefore, listOfStringType);
System.out.println(stringsJson);
final List<String> stringsAfter = gson.fromJson(stringsJson, listOfStringType);
System.out.println(stringsAfter);
}
输出:
之前打包:
JSON:{}
之后打包:null null -- [!]不是"'"
打包前:foo
JSON:{“foo”:“foo”}
打包后:foo空--[!]不是福“
打包前:bar
JSON:{“bar”:“bar”}
打包后:空条--[!]不是“酒吧”
打包前:foo-bar
JSON:{“foo”:“foo”,“bar”:“bar”}
打包后:foo-bar
[foo,bar][br>,“foo”,“bar][br>[foo,bar]
然而,我不认为编写复杂的(反)序列化策略是一个好的选择,而且您可能对重新设计DTO和数据(反)序列化感兴趣。此外,“
是一个值,而null
不是——我永远不会把它们混合在一起,我会修改为什么你的系统是这样设计的(这看起来真的像是一个空/空值混合的问题)。
我想在Java中反序列化包含空值的json字符串。我想将对象反序列化为对象。json字符串类似于: 当我反序列化使用 由于对象中的that,我得到一个空指针异常。我如何指示Gson忽略空值的反序列化?
我尝试将以下json反序列化为java POJO。 我使用jackson 2.8.6 但我不断得到以下例外情况: 如果我为它添加一个字符串设置器 摘要:一些(设计错误的)API发送给我的是空字符串()而不是,我不得不告诉Jackson忽略这个错误的值。我怎么能这么做?
问题内容: 我目前正在使用杰克逊2.1.4,并且在将对象转换为JSON字符串时忽略字段时遇到了一些麻烦。 这是我的类,它充当要转换的对象: 这是我如何转换它: 这是输出: 如何避免这些空值?我只想获取“订阅”目的所需的信息! 这正是我要查找的输出: 我还尝试了@JsonInclude(Include.NON_NULL)并将所有变量都设置为null,但是它也不起作用!感谢您的帮助! 问题答案: 您将
下面是我的类,它充当要转换的对象: 下面是我的转换方法: 输出如下: 下面正是我要查找的输出: 我还尝试了@jsonInclude(include.non_null),并将我的所有变量置为null,但也没有起作用!谢谢你们的帮助!
我试图反序列化这个json对象数组: 我的java类看起来像这样: 问题在于json的tags属性,它可以是空字符串或数组。现在gson给了我一个错误: 我应该如何反序列化这个json? 我对这个json没有任何控制,它来自第三方api。
我读过@JsonInclude这样的问题来忽略空值。这适用于实体中的常规字段,但不适用于集合。如果实体中的集合为空,Json序列化会给出一个空值。 如何对集合进行等效忽略?