我使用ember.js作为客户端框架。开箱即用,此框架需要某种格式的 JSON。我正在尝试让杰克逊输出这种格式。这对于回答这个问题并不重要,但提到它并标记它,因为它可以帮助更多处于相同情况的用户。
基本上,我希望每个引用的对象(不是根对象)都作为它们的 id 输出。我会给你一个简单的例子。这些类:
public abstract class BaseEntity{
protected Long id;
}
public class Resource{
private String name;
private AnotherResource subResource;
private List<AnotherResource> subResources;
//getters and setters
}
public class SubResource{
private String value;
//getters and setters
}
使用这些示例实例:
// Sub resources
SubResource sr1 = new SubResource();
sr1.setId(2);
sr1.setValue("some string");
SubResource sr2 = new SubResource();
sr2.setId(3);
sr2.setValue("some string");
SubResource sr3 = new SubResource();
sr3.setId(4);
sr3.setValue("some string");
// resource
Resource r = new Resource();
r.setId(1);
r.setName("bla");
r.setSubResource(sr1);
ArrayList<SubResource> list = new ArrayList<SubResource>();
list.add(sr1);
list.add(sr2);
list.add(sr3);
r.setSubResources(list);
序列化r
应该输出:
{
"resource":{
"id": 1,
"name": "bla",
"sub_resource_id": 2,
"sub_resource_ids": [
1,
2,
3
]
}
}
我们可以在这里注意到几件事:
- 键名与
"_id"
or连接"_ids"
,具体取决于它是被引用对象还是被引用对象的集合 - 只有引用对象的 id被序列化
- 在引用对象的集合的情况下,它们的 id 数组被序列化
关于属性名称(1),我已经用@JsonProperty
注释对其进行了整理。
至于其余的,我编写了以下序列化程序:
public class BaseEntityIdSerializer extends JsonSerializer<BaseEntity> implements ContextualSerializer {
public void serialize(BaseEntity value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
}
@Override
public void serializeWithType(BaseEntity value, JsonGenerator jgen,
SerializerProvider provider, TypeSerializer typeSer)
throws IOException, JsonProcessingException {
serialize(value, jgen, provider);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov,
BeanProperty property) throws JsonMappingException {
if(property.getType().isCollectionLikeType()){
return new BaseEntityIdCollectionSerializer();
} else {
return new BaseEntityIdSimpleSerializer();
}
}
public class BaseEntityIdSimpleSerializer extends StdSerializer<BaseEntity>{
public BaseEntityIdSimpleSerializer(){
super(BaseEntity.class);
}
@Override
public void serialize(BaseEntity value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonGenerationException {
jgen.writeNumber(value.getId());
}
@Override
public void serializeWithType(BaseEntity value, JsonGenerator jgen,
SerializerProvider provider, TypeSerializer typeSer)
throws IOException, JsonProcessingException {
serialize(value, jgen, provider);
}
}
public class BaseEntityIdCollectionSerializer extends StdSerializer<Collection<? extends BaseEntity>>{
public BaseEntityIdCollectionSerializer(){
super(Collection.class, false);
}
@Override
public void serialize(Collection<? extends BaseEntity> value,
JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException {
jgen.writeStartArray();
for(BaseEntity b:value){
jgen.writeNumber(b.getId());
}
jgen.writeEndArray();
}
@Override
public void serializeWithType(Collection<? extends BaseEntity> value, JsonGenerator jgen,
SerializerProvider provider, TypeSerializer typeSer)
throws IOException, JsonProcessingException {
serialize(value, jgen, provider);
}
}
}
然后用@JsonSerialize(using=BaseEntityIdSerializer.class)
这可以完成工作。输出正确的 JSON。但是我觉得我在重复很多代码。例如,我正在为集合和单个对象编写不同的序列化程序类。我希望多次使用单个序列化程序。更可组合的东西。显然我使用了错误的类来解析序列化程序(我被迫实现serialize
但我什么都不做)。
你有什么见解?如何改进此序列化程序?此外,是否可以在序列化程序中处理属性名称(连接“_id”)?这样我就可以不用@JsonProperty
注释了。
谢谢。