如何通过Jackson防止Map中的空值和bean中的空字段被序列化。

62
我有一个 Map<String,Foo> foosMap,想通过 Jackson 序列化它。现在我希望在序列化过程中实现以下两个设置:
  1. 该 Map 可能包含大量的 null 值和 null 键,我不希望将它们序列化。
  2. 对于正在被序列化的所有 Foos,我不想序列化其中引用的 null 对象。
如何实现最佳结果?我的项目中使用 jackson-core1.9 和 jackson-mapper1.9 jar 包。

可能是重复问题,请查看此链接:https://dev59.com/t3A75IYBdhLWcg3wuLnD - dbf
映射表最多只能有一个空键。 - amicngh
@dbf 不太对,请再看一下编辑后的问题标题。 - Inquisitive
@dbf 还有被接受的答案中提到的那种方法现在似乎已经过时了。 - Inquisitive
4个回答

128
如果修改原始的Map数据结构以更好地表示希望序列化的实际值是合理的,那可能是一个不错的方法,这可能会减少需要进行的Jackson配置。例如,在调用Jackson之前,尽可能删除null键条目。话虽如此...

为了禁止序列化具有null值的Map条目:
在Jackson 2.9之前,您仍然可以使用WRITE_NULL_MAP_VALUES,但请注意它已经移动到SerializationFeature
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);

自Jackson 2.9版本以来

WRITE_NULL_MAP_VALUES已经被弃用,您可以使用以下等效方式:

mapper.setDefaultPropertyInclusion(
   JsonInclude.Value.construct(Include.ALWAYS, Include.NON_NULL))
为了抑制序列化具有空值的属性,您可以直接配置ObjectMapper,或利用@JsonInclude注释:
mapper.setSerializationInclusion(Include.NON_NULL);

或者:

@JsonInclude(Include.NON_NULL)
class Foo
{
  public String bar;

  Foo(String bar)
  {
    this.bar = bar;
  }
}

为了处理空的 Map 键,需要进行一些自定义序列化,据我所知。

null 键序列化为空字符串的简单方法(包括先前提到的两个配置的完整示例):


import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    Map<String, Foo> foos = new HashMap<String, Foo>();
    foos.put("foo1", new Foo("foo1"));
    foos.put("foo2", new Foo(null));
    foos.put("foo3", null);
    foos.put(null, new Foo("foo4"));

    // System.out.println(new ObjectMapper().writeValueAsString(foos));
    // Exception: Null key for a Map not allowed in JSON (use a converting NullKeySerializer?)

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
    mapper.setSerializationInclusion(Include.NON_NULL);
    mapper.getSerializerProvider().setNullKeySerializer(new MyNullKeySerializer());
    System.out.println(mapper.writeValueAsString(foos));
    // output: 
    // {"":{"bar":"foo4"},"foo2":{},"foo1":{"bar":"foo1"}}
  }
}

class MyNullKeySerializer extends JsonSerializer<Object>
{
  @Override
  public void serialize(Object nullKey, JsonGenerator jsonGenerator, SerializerProvider unused) 
      throws IOException, JsonProcessingException
  {
    jsonGenerator.writeFieldName("");
  }
}

class Foo
{
  public String bar;

  Foo(String bar)
  {
    this.bar = bar;
  }
}

为了防止将键为nullMap条目序列化,需要进行进一步的自定义序列化处理。


2
请注意,这些指令仅适用于Jackson 2.0(com.fasterxmlorg.codehaus不同)。 - Adam Gent
@ProgrammerBruce - 在对象映射器中,是否有可能防止特定类的空字段序列化? 例如:使用相同的对象映射器对类A和B进行序列化,但仅忽略类B中的空字段。 - CodeNameGrant
@ProgrammerBurce - 由于Jackson已升级到2.9,WRITE_NULL_MAP_VALUES已被弃用。你知道有没有替代方法来实现同样的功能吗? - Aiden Zhao
我发现自2.9以来WRITE_NULL_MAP_VALUES的等效方法是:mapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(Include.ALWAYS, Include.NON_NULL)) - Aiden Zhao
@AidenZhao - 我有jackson 2.9.2版本。我的IDE,Intellij IDEA没有显示出com.fasterxml.jackson.databind.ObjectMapper中名为 "setDefaultPropertyInclusion" 的任何方法。我漏掉了什么吗? - MasterJoe

19

对于版本小于2.0的Jackson,请在被序列化的类上使用此注解:

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

5
注意,这已经被弃用了,上面的被接受的答案包含了最新的注释:@JsonInclude(Include.NON_NULL)。 - Amber
请注意,如果您使用的是Jackson 1.9.x,则无法使用JsonInclude注释,此时您将需要使用JsonSerialize注释。 - Suketu Bhuta
我确认在Jackson 1.9.x版本中,@JsonInclude(Include.NON_NULL)无法正常工作。我正在导入以下包:org.codehaus.jackson.map。 - Emanuele

3

答案看起来有些过时了,我所做的是使用这个映射器将 MAP 转换为目标类型。

      ObjectMapper mapper = new ObjectMapper().configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);
一个简单的Map:
          Map<String, Object> user = new HashMap<String,Object>();
            user.put( "id",  teklif.getAccount().getId() );
            user.put( "fname", teklif.getAccount().getFname());
            user.put( "lname", teklif.getAccount().getLname());
            user.put( "email", teklif.getAccount().getEmail());
            user.put( "test", null);

例如,您可以像这样使用它:

      String json = mapper.writeValueAsString(user);

2
请添加 JSON 的输出。 - nitinsridar

-1

我的解决方案,希望能够帮到你
自定义ObjectMapper并在Spring XML中进行配置(注册消息转换器)

public class PyResponseConfigObjectMapper extends ObjectMapper {
public PyResponseConfigObjectMapper() {
    disable(SerializationFeature.WRITE_NULL_MAP_VALUES); //map no_null
    setSerializationInclusion(JsonInclude.Include.NON_NULL); // bean no_null
}

}


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