Jackson中的动态序列化(使用注释删除字段)

时间:2018-06-19 18:01:33

标签: jackson

沿着创建注释的路径前进,该注释将动态确定字段是否应该序列化。

注释的实现如下:

arr_2

现在为序列化器提供代码:

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = HiddenFieldSerializer.class)
@Target(value = ElementType.FIELD)
public @interface Hidden {

}

一些代码来说明其工作原理:

public class HiddenFieldSerializer extends StdSerializer<String> implements ContextualSerializer {

  public HiddenFieldSerializer() {
    super(String.class);
  }

  @Override
  public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) {
    try {
      provider.defaultSerializeNull(jgen);
    } catch (IOException e) {
    }
  }

  @Override
  public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
    return shouldHide() ? new HiddenFieldSerializer() : new StringSerializer();
  }

  public boolean shouldHide() {
    /* Simplifying this */
    return Boolean.TRUE;
  }
}

输出如下:

public class Test {

  static final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(Include.NON_NULL)
      .setSerializationInclusion(
          Include.NON_EMPTY);


  static class User {

    @JsonProperty
    String username;

    @Hidden
    @JsonProperty
    String pin;
  }

  public static void main(String... args) throws JsonProcessingException {
    final POC.User u = new POC.User();
    u.username = "harry_potter";
    u.pin = "1298";

    System.out.println(mapper.writeValueAsString(u));
  }

}

如何将现场引脚从序列化中删除而不是将其为null?显然,在这种情况下,设置映射器的属性的用户很少。有什么建议么?有什么想法吗?也许整件事是个坏主意?

理想情况下,我应该能够看到以下内容:

{"username":"harry_potter","pin":null}

1 个答案:

答案 0 :(得分:1)

不清楚是要静态地忽略给定的属性还是动态地忽略给定的属性。无论如何,看起来您已经对其进行了过度设计。

首先,我想确保您之前遇到过@JsonIgnore。如果它不符合您的需求,则可以定义自定义忽略注释,如下所示:

@Retention(RetentionPolicy.RUNTIME)
public @interface Hidden {

}

然后选择最适合您需求的方法:

方法1

扩展JacksonAnnotationIntrospector并覆盖检查忽略标记的方法:

public class CustomAnnotationIntrospector extends JacksonAnnotationIntrospector {

    @Override
    public boolean hasIgnoreMarker(AnnotatedMember m) {
        return super.hasIgnoreMarker(m) || m.hasAnnotation(Hidden.class);
    }
}

配置ObjectMapper以使用您的注释内省者:

ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new CustomAnnotationIntrospector());

注释内省每个类仅出现一次,因此您不能动态更改使用的条件(如果有)。可以在此answer中看到类似的示例。

方法2

扩展BeanSerializerModifier来修改将要序列化的属性:

public class CustomBeanSerializerModifier extends BeanSerializerModifier {

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, 
            BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {

        return beanProperties.stream()
                .filter(property -> property.getAnnotation(Hidden.class) == null)
                .collect(Collectors.toList());
    }
}

然后将其添加到Module并将其注册到您的ObjectMapper

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SimpleModule() {

    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);
        context.addBeanSerializerModifier(new CustomBeanSerializerModifier());
    }
});

这种方法允许您动态忽略属性。