json 如何在序列化过程中跳过某些类型的字段?

dohp0rv5  于 2023-11-20  发布在  其他
关注(0)|答案(3)|浏览(206)

我有一个Spring AOP服务,它拦截了很多不同的第三方控制器端点。我的服务运行一个端点,获取结果DTO,使用ObjectMapper将DTO序列化为json,将json发送到Kafka并将DTO返回外部。问题是:服务不应序列化特定类型字段(例如MultipartFile)。我不能使用@JsonIgnore注解,因为DTO应该在没有更改的情况下返回。我可以让ObjectMapper跳过某些类型的字段吗?或者,复制DTO并使用反射将此字段设置为null?

irlmq6kh

irlmq6kh1#

永远记住,Jackson是字面上的魔术,是无限可定制的:)
有很多方法可以实现你想要的。
假设您有以下DTO类,并希望排除File

public class SimpleDTO {

    private final File file;
    private final String name;

    @JsonCreator
    public SimpleDTO(@JsonProperty("file") File file, @JsonProperty("name") String name) {
        this.file = file;
        this.name = name;
    }

    public File getFile() {
        return file;
    }

    public String getName() {
        return name;
    }
}

字符串

Mix-ins

您可以创建一个mix-in,例如:

@JsonIgnoreType
public interface IgnoreTypeMixin {}


然后在序列化时使用它:

//Pretend the File class was annotated by @JsonIgnoreType
ObjectMapper mapper = new ObjectMapper().addMixIn(File.class, IgnoreTypeMixin.class);

String serialized = mapper.writeValueAsString(new SimpleDTO(new File("/tmp/simple.txt"), "A kewl name"));
System.out.println(serialized); //Prints {"name":"A kewl name"}


除了@JsonIgnoreType,你还可以在SimpleDTO@JsonIgnoreProperties(value = { "file" })或任何其他Jackson注解中的file字段中混入@JsonIgnore
注意:不要每次都创建一个新的ObjectMapper。配置一个示例用于序列化并永久共享。

程序化配置

Mix-ins允许你从外部添加注解,但是注解仍然是静态配置。如果你必须动态地选择要忽略的字段(不仅仅是类型),注解,不管是否混合,都是不够的。Jackson,是魔术师,让你通过编程实现任何可以通过注解完成的事情:

public class FieldFilteringIntrospector extends NopAnnotationIntrospector {

    private final Set<Class<?>> ignoredTypes;

    public FieldFilteringIntrospector(Set<Class<?>> ignoredTypes) {
        this.ignoredTypes = Collections.unmodifiableSet(ignoredTypes);
    }

    public FieldFilteringIntrospector(Class<?>... ignoredTypes) {
        this.ignoredTypes = Arrays.stream(ignoredTypes).collect(Collectors.toUnmodifiableSet());
    }

    @Override
    public Boolean isIgnorableType(AnnotatedClass ac) {
        return ignoredTypes.contains(ac.getRawType());
    }
}


然后在序列化时使用它:

SimpleModule module = new SimpleModule("type-filter-module") {
    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);
        context.insertAnnotationIntrospector(new FieldFilteringIntrospector(File.class));
    }
};
ObjectMapper mapper = new ObjectMapper().registerModule(module);

String serialized = mapper.writeValueAsString(new SimpleDTO(new File("/tmp/simple.txt"), "A kewl name"));
System.out.println(serialized); //Prints {"name":"A kewl name"}


通过覆盖NopAnnotationIntrospector中的其他方法,可以模拟其他注解、@JsonIgnore和其他注解。
注意:同样,ObjectMapper只创建一次。

ekqde3dh

ekqde3dh2#

您可以使用对象Map器来克服这个问题,或者可以使用getDeclaredFields方法来构建一个逻辑来删除不需要的属性并返回

bvjveswy

bvjveswy3#

我在YAML属性文件中有可更改的禁止类列表,所以我不能使用mixin。任务是这样解决的:

@Value("${classes-to-remove}")
private String classesToRemove;

public String getClearedJson(MyDTO myDTO) {
    List<String> fieldNamesToRemove = new ArrayList<>();

    for (Field field: myDTO.getClass().getDeclaredFields()) {
        if (classesToRemove.contains(field.getType().getSimpleName())) {
            fieldNamesToRemove.add(field.getName());
            continue;
        }

        if (field.getGenericType() instanceof ParameterizedType) {
            ParameterizedType listType = (ParameterizedType) field.getGenericType();
            Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
            if (classesToRemove.contains(listClass.getSimpleName())) {
                fieldNamesToRemove.add(field.getName());
            }
        }
    }

    String json = objectMapper.writeValueAsString(myDTO);
    JsonNode jsonNode = objectMapper.readTree(json);
    ObjectNode object = (ObjectNode) jsonNode;
    fieldNamesToRemove.forEach(object::remove);
    String updatedJson = objectMapper.writeValueAsString(object);
    
    return updatedJson;
}

字符串

相关问题