2015-03-18 87 views
1

在我使用Spring的Web应用程序中,我们想要使用自定义的JSON结构。 Spring缺省需要这样一个POJO:Spring框架JSON序列化到数组而不是对象

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类型,但只是将包装对象更改为数组而不是和对象使用fi视场。

这是迄今为止我已经使用的序列化程序(将使用@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工作作为默认的人做(而不只是Model类,但任何类似或子类,我们需要序列化数组)?这可能具有混合属性,并且没有特定的属性命名约定。

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

+1

串行器是正确的方法。 – 2015-03-18 21:33:35

+0

啊,是的。我需要澄清,因为我希望序列化程序不是特定于一个Model类,而是与任何POJO一起工作并相应地动态构建数组。谢谢! – Cameron 2015-03-18 21:53:45

+1

因此,您需要'[1]',而不是'{“id”:[1]}'而不是'{“id”:1}'? – 2015-03-18 21:54:53

回答

0

Apache BeanUtils library看看,特别要注意BeanUtils.populate()方法。

该方法的作用是将任何给定的Object转换为基于JavaBeans约定的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>准备使用标准的弹簧机构序列化。我甚至相信你将不再需要特定的串行:

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

免责声明:

请以此为指导,而不是作为一个最终的解决方案。我试图尽可能小心,但代码可能有错误。我很确定它需要特殊处理阵列和POJO的Iterable。毫无疑问,缺乏异常处理。它仅适用于POJO。如果提供的对象具有循环引用,它可能会爆炸。它没有测试!

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}; 
    } 
} 
+0

这将工作的一个具体实例。我已经更新了这个问题,以澄清我正在寻找更通用的解决方案。谢谢! – Cameron 2015-03-18 22:31:47

+0

在这种情况下,我会使用mixin注释(http://wiki.fasterxml.com/JacksonMixInAnnotations)。您可以创建一个接口(或抽象类),并使用用'@ JsonValue'注释的value方法,并在所有类中实现这个mixin接口。此外,你可以在ObjectMapper的配置中指定这个mixin,并且实际上不会改变你自己的类。 – Advanced 2015-03-19 23:53:14