适用于Collection类的Spring Boot自定义序列化器

时间:2019-03-19 12:04:23

标签: java spring-boot jackson

我试图为我对象的一个​​属性实现自定义序列化程序,以便当我从REST控制器返回它时获得不同的JSON结构。

我的约束是我无法更改REST控制器或模型类的接口(因此我无法添加额外的注释等,这可能会使此操作变得更容易)。我唯一能想到的是,使其呈现与模型中描述的不同的是自定义序列化程序,如果有更好的方法,请随时告诉我在约束范围内的另一种方法。

我的模型如下所示:

public class WrapperModel {

  // a lot of autogenerated fields

  List<Property> properties;

  // getters/setters
}

public class Property {

  private String name;

  private String value;

  // getters / setters

}

所以当渲染时看起来像这样:

{   ....   
    "properties": [
      {"key1": "value1"}, {"key2": "value2"},...   
    ] 
}

我想要的是这个

{   ....   
    "properties": {
      "key1": "value1",
      "key2": "value2",
      ...  
    }
}

序列化器很容易:

public class PropertyListJSONSerializer extends StdSerializer<List<Property>> {

//....

@Override
public void serialize(List<Property> value, JsonGenerator gen,   SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    for(Property p: value){
        gen.writeStringField(p.getName(), p.getValue());
    }
    gen.writeEndObject();
}

}

现在,当我尝试在@Configuration文件中注册此序列化器时:

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

    SimpleModule module = new SimpleModule();
    module.addSerializer(List<Property>.class, new PropertyListJSONSerializer());
    mapper.registerModule(module);

    return mapper;
}

这是行不通的,因为List<Property>.class是模板类,因此不能用于addSerializer。还有其他添加此序列化器的方法或执行类似操作的方法吗?

我不想为WrapperModel添加自定义序列化程序,因为该类是自动生成的,并且可以添加和删除字段。这无需修改应用程序代码就可以实现(如果我有一个自定义的序列化程序,则还需要从序列化程序中添加/删除字段(?))。或者,有没有一种方法可以对类使用Standard序列化程序,并手动处理此List<>字段。

模型类是由Spring Boot openapi代码生成器生成的,因此我可以在模型字段的顶部放置一组非常有限的JSON注释(如果有注释的方法,请不要犹豫地发布)检查openapi源代码(如果支持该特定注释)。但是我更愿意为List<Property>使用自定义序列化程序,或者为WrapperModel编写一个序列化程序,为StdSerializer使用所有内容并且仅处理List自己财产。

1 个答案:

答案 0 :(得分:1)

MixIn

在这种情况下,我们需要使用MixIn功能。创建如下界面:

interface WrapperModelMixIn {

    @JsonSerialize(using = PropertyListJSONSerializer.class)
    List<Property> getProperties();
}

并按如下所示进行注册:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(WrapperModel.class, WrapperModelMixIn.class);

较旧的提案

您需要使用允许注册通用类型的序列化器的Jackson类型。更改后的序列化器如下所示:

class PropertyListJSONSerializer extends StdSerializer<List<Property>> {

    public PropertyListJSONSerializer(JavaType type) {
        super(type);
    }

    @Override
    public void serialize(List<Property> value, JsonGenerator gen, SerializerProvider provider)
        throws IOException {
        gen.writeStartObject();
        for (Property p : value) {
            gen.writeStringField(p.getName(), p.getValue());
        }
        gen.writeEndObject();
    }
}

您可以按如下所示进行注册:

ObjectMapper mapper = new ObjectMapper();

CollectionType propertiesListType = mapper.getTypeFactory().constructCollectionType(List.class, Property.class);
SimpleModule module = new SimpleModule();
module.addSerializer(new PropertyListJSONSerializer(propertiesListType));
mapper.registerModule(module);