Spring 框架 JSON 序列化为数组而不是对象

Spring Framework JSON Serialization to Array rather than Object

在我使用 Spring 的 Web 应用程序中,我们希望使用自定义 JSON 结构。 Spring 默认采用这样的 POJO:

public class Model {

    private int id;
    private String name;

    public Model(){}

    public Model(int id, String name){
        this.id = id;
        this.name = name;
    }
}

然后把它变成这样:

{"id":1, "name":"Bob"}

对于我们的应用程序,我们希望将它变成这样:

[1, "Bob"]

我想使用 Spring 的默认序列化逻辑来检测 Java 类型(int、String、Collection 等)并映射到适当的 JSON 类型,但只需将包装对象更改为数组而不是带字段的对象。

这是我目前拥有的序列化程序(将在模型中使用@JsonSerialize(using = Serializer.class) 实现),但不想重写所有逻辑 Spring已实施。

public class Serializer extends JsonSerializer<Model> {
    @Override
    public void serialize(Model value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {

        jgen.writeStartArray();
        jgen.writeString(value.id);
        .... other values ...
        jgen.writeEndArray();

    }
}

我怎样才能连接到预先存在的序列化器,以便这个新的序列化器可以像默认序列化器一样与任何 POJO 一起工作(不仅仅是模型 class,而是任何类似的或子序列化器 class 我们需要序列化到一个数组)?这可能具有混合属性,并且没有特定的属性命名约定。

我想避免为每个不同的模型 class(...其他值...)部分编写自定义序列化程序。

您可以为此使用 @JsonValue 注释。 示例:

public class Model {

  private int id;

  public Model(){}

  public Model(int id){
    this.id = id;
  }

  @JsonValue
  public int[] getValue() {
    return new int[]{this.id};
  } 
}

看看Apache BeanUtils library, in particular, pay attention to the BeanUtils.populate()方法。

该方法的作用是根据 JavaBeans 约定将任何给定的 Object 转换为 Map<String, Object>。在键中,您将拥有属性名称,而在值中,您将拥有每个属性的值。该方法对于标准情况应该足够了。仔细阅读文档,检查如何处理特殊情况。

Model model = ...; // get your model from some place

Map<String, Object> properties = new HashMap<>();

BeanUtils.populate(model, properties);

// Exception handling and special cases left as an excercise

上面递归地填充properties映射,这意味着如果你的Model有一个名为otherModel的属性,其类型是OtherModel,那么properties 映射将在与 otherModel 键匹配的条目处有另一个映射,对于其他嵌套的 POJO 依此类推。

获得 properties 映射后,您想要序列化为数组元素的内容将包含在其值中。所以,像这样的东西应该可以完成工作:

public List<Object> toArray(Map<String, Object> properties) {
    List<Object> result = new ArrayList<>();

    for (Object obj : properties.values()) {
        Object elem = null;
        if (obj != null) {
            Class<?> clz = obj.getClass();
            if (Map.class.isAssignableFrom(clz)) {
                elem = toArray((Map<String, Object>) obj); // recursion!
            } else {
                elem = obj;
            }
        }
        result.add(elem); // this adds null values
                          // move 1 line up if you don't
                          // want to serialize nulls
    }
    return result;
}

然后,在调用 toArray() 方法后,您将有一个 List<Object> 准备好使用标准 Spring 机制进行序列化。我什至相信您不需要特定的序列化程序:

List<Object> array = toArray(properties);
return array; // return this array, i.e. from a Controller 

免责声明:

请将其用作指南,而不是最终解决方案。我尽量小心,但代码可能有错误。我很确定它需要对数组和 Iterables 的 POJO 进行特殊处理。毫无疑问,它缺乏异常处理。它仅适用于 POJO。如果提供的对象具有循环引用,它可能会爆炸。未经测试!