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