У меня бин определен так:
public static class TestBean {
private String a;
private Long b;
public TestBean(String a, Long b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public Long getB() {
return b;
}
}
Это моделирует некоторый бизнес, и я не могу его реализовать (используя JPA). Некоторые из моих API позволяют пользователю получать представление этого сериализованного компонента в виде JSON с использованием Jackson (через JAX-RS), и я хотел бы добавить список связанных ссылок на это представление.
Обычная сериализация JSON Джексона будет (для a = "aa" и b = 2L):
{"a":"aa","b":2}
И я бы хотел, чтобы ссылки отображались как
{"a":"aa","b":2,
"links":[{"rel":"rel","href":"href://"},{"rel":"rel2","href":"href://2"}]}
Возможное решение
Я бы не стал добавлять метод getLinks () в мой bean-компонент, он специфичен для этого представления.
Простое использование составного объекта приведет к сериализации, например:
{"data":{"a":"aa","b":2},"links":[{"rel":"rel","href":"href://"}]}
С которым я мог бы жить, но это не то, что я искал в конечном итоге.
Текущее решение
Я бы хотел избежать манипулирования строкой JSON или необходимости перезагружать ее в Map для вставки моих дополнительных значений. На данный момент решение, которое я придумала, кажется ужасно запутанным:
Текущее страшное решение:
//a composite view object
public abstract class AddedLinksView<K> {
private final K resource;
private final Link[] links;
public AddedLinksView(K resource) {
this.resource = resource;
links = buildLinks(resource);
}
public abstract Link[] buildLinks(K resource);
public K getResource() {
return resource;
}
public Link[] getLinks() {
return links;
}
}
//a specific bean serializer
private static class RawBeanSerializer extends BeanSerializer {
public RawBeanSerializer(BeanSerializerBase ser) {
super(ser);
}
//this is like the standard serialize but without the start and end tags
public void rawSerialize(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException,
JsonGenerationException {
if (_propertyFilterId != null) {
serializeFieldsFiltered(bean, jgen, provider);
} else {
serializeFields(bean, jgen, provider);
}
}
}
@Test
public void usingModule() throws Exception {
// basic module metadata just includes name and version (both for troubleshooting; but name needs to be unique)
SimpleModule module = new SimpleModule("EnhancedDatesModule", new Version(0, 1, 0, "alpha"));
//adding a serializer for the composite view
module.addSerializer(new JsonSerializer<AddedLinksView>() {
@Override
public Class<AddedLinksView> handledType() {
return AddedLinksView.class;
}
@Override
public void serialize(AddedLinksView value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
//looking up the bean serializer that will be used for my resource
JsonSerializer<Object> ser = provider.findTypedValueSerializer(value.getResource().getClass(), true,
null);
if (ser instanceof BeanSerializerBase) {
//cloning it in a sub class that makes it possible to 'inline' the serialization
RawBeanSerializer openSer = new RawBeanSerializer((BeanSerializerBase) ser);
openSer.rawSerialize(value.getResource(), jgen, provider);
}
//adding my links
jgen.writeArrayFieldStart("links");
for (Link link : value.getLinks()) {
jgen.writeObject(link);
}
jgen.writeEndArray();
jgen.writeEndObject();
}
});
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
AddedLinksView<TestBean> view = new AddedLinksView<TestBean>(new TestBean("aa", 2L)) {
@Override
public Link[] buildLinks(TestBean resource) {
return new Link[] { new Link("rel", "href://"), new Link("rel2", "href://2") };
}
};
System.out.println("useModule json output: " + mapper.writeValueAsString(view));
}
Я упустил что-то очевидное в Джексоне, чтобы добиться этого? Или я уже полностью не отвечаю требованиям?