Spring Framework JSON序列化到数组而不是Object

时间:2015-03-18 21:31:55

标签: java json spring spring-mvc serialization

在我使用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的模型中实现(使用= 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();

    }
}

如何挂钩预先存在的Serializer,以便这个新的序列化程序可以像任何POJO一样工作(不仅仅是Model类,而是我们需要序列化到数组的任何类似或子类)?这可能具有混合属性,并且没有特定的属性命名约定。

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

2 个答案:

答案 0 :(得分:0)

您可以使用@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};
  } 
}

答案 1 :(得分:0)

请注意Apache BeanUtils library,尤其要注意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 

免责声明:

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