Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Gson序列化一般忽略空字符串_Java_Gson - Fatal编程技术网

Java Gson序列化一般忽略空字符串

Java Gson序列化一般忽略空字符串,java,gson,Java,Gson,有没有一种通用的方法告诉Gson不要写空字符串 我非常不喜欢必须实现一个TypeAdapter,它可以按照某种程度上的建议处理每个字段。某种程度上。据我所知,Gson不允许您对对象字段进行太多的控制,我所知道的唯一一个控件是您可以使用它@JsonAdapter。比如说, import com.google.gson.annotations.JsonAdapter; 最终课程包{ @JsonAdapter(EmptyStringTypeAdapter.class) 最终字符串foo; @JsonA

有没有一种通用的方法告诉Gson不要写空字符串


我非常不喜欢必须实现一个TypeAdapter,它可以按照某种程度上的建议处理每个字段。

某种程度上。据我所知,Gson不允许您对对象字段进行太多的控制,我所知道的唯一一个控件是您可以使用它
@JsonAdapter
。比如说,

import com.google.gson.annotations.JsonAdapter;
最终课程包{
@JsonAdapter(EmptyStringTypeAdapter.class)
最终字符串foo;
@JsonAdapter(EmptyStringTypeAdapter.class)
最后一根弦杆;
专用包(最终字符串foo、最终字符串条){
this.foo=foo;
这个.bar=bar;
}
静态数据包(最终字符串foo、最终字符串条){
退回新包装(foo、bar);
}
@凌驾
公共字符串toString(){
返回foo+“”+条;
}
}
尽管它对某些人来说可能看起来很乏味,但它可以让您完全控制数据传输对象,让您可以选择如何处理这个或那个字符串。示例类型适配器可能如下所示:

final类EmptyStringTypeAdapter
扩展类型适配器{
私有EmptyStringTypeAdapter(){
}
@凌驾
@抑制警告(“资源”)
public void write(final JsonWriter JsonWriter,@Nullable final String s)
抛出IOException{
如果(s==null | | s.isEmpty()){
jsonWriter.nullValue();
}否则{
jsonWriter.value;
}
}
@凌驾
@非空
@SuppressWarnings(“EnumSwitchStatementWhichmisseCases”)
公共字符串读取(最终JsonReader JsonReader)
抛出IOException{
最终的JsonToken标记=jsonReader.peek();
交换机(令牌){
大小写为空:
返回“”;
大小写字符串:
返回jsonReader.nextString();
违约:
抛出新的IllegalStateException(“意外标记:+token”);
}
}
}
这里需要注意的一点是,它无法从空字符串中恢复空字符串(不幸的是,您在这里遇到了不可逆的转换),因此您可能还需要了解如何在读取时恢复
@JsonAdapter(EmptyStringTypeAdapter.class)
-注释字段。示例测试:

private static final Gson Gson=new Gson();
私有静态最终类型listOfStringType=new-TypeToken(){
}.getType();
公共静态void main(最终字符串…参数){
//单一元素
不可修改的列表(共包(“,”)、共包(“,”)、共包(“,”条”)、共包(“,”条”)、共包(“,”条”))
.stream()
.peek(pack->System.out.println(“之前打包:+pack))
.map(gson::toJson)
.peek(json->System.out.println(“json:+json))
.map(json->gson.fromJson(json,Pack.class))
.peek(pack->System.out.println(“打包后:+pack))
.forEach(pack->System.out.println());
//多元
最终列表stringsBefore=ImmutableList.of(“,”foo“,”bar”);
System.out.println(stringsBefore);
最终字符串stringsJson=gson.toJson(stringsBefore,listOfStringType);
System.out.println(stringsJson);
最终列表stringsAfter=gson.fromJson(stringsJson,listOfStringType);
System.out.println(stringsAfter);
}
输出:

之前打包:
JSON:{}
打包后:null--[!]不是“”“

包装前:foo
JSON:{“foo”:“foo”}
打包后:foo空--[!]非foo“”

打包前:酒吧
JSON:{“bar”:“bar”}
打包后:空栏--[!]不是“”栏

打包前:foo-bar
JSON:{“foo”:“foo”,“bar”:“bar”}
打包后:foo-bar

[,foo,bar]
[“”,“foo”,“bar”]
[,foo,bar]


然而,我不认为编写复杂的(反)序列化策略是一个好的选择,您可能会对重新设计DTO和数据(反)序列化感兴趣。此外,
是一个值,而
null
不是一个值——我决不会混合使用它们,我会修改系统以这种方式设计的原因(这看起来真的像是空/空值混合问题)。

感谢@Lyubomyr的回答,但我找到了一个更适合我们用例的解决方案:

如果我们将所有空字符串和对象设置为null,序列化后剩余的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);
  }

性能,但运行速度相当快。如果有大量空字段,则可以节省时间(和空间)当序列化和发送/写入数据库时。

这可能会有所帮助吗?谢谢,但我已经发现了这一点,我不太明白如何实现它或它如何在所有字段上循环。虽然我不同意你的观点,这是一个潜在的问题,但我们现在有一个新需求的性能问题,我们没有时间重新设计一切。'_(ツ)_/¯