Различные выходные данные JSON при использовании настраиваемого сериализатора json в Spring Data Rest
После добавления кастома Jackson
Сериализатор, основанный на официальной документации, я наблюдал немного другой формат вывода json.
Этот пример основан на развилке пружинных перестановок.
простираться org.springsource.restbucks.WebConfiguration
от RepositoryRestMvcConfiguration
и переопределить configureJacksonObjectMapper
:
@Override
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
final SimpleSerializers serializers = new SimpleSerializers();
serializers.addSerializer(Order.class, new OrderSerializer());
objectMapper.registerModule(new SimpleModule("CustomSerializerModule"){
@Override public void setupModule(SetupContext context) {
context.addSerializers(serializers);
}
});
}
Создать класс org.springsource.restbucks.order.OrderSerializer
, Ради краткости просто напишите атрибут paid
как JSON.
public class OrderSerializer extends JsonSerializer<Order> {
@Override
public void serialize(Order value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
jgen.writeBooleanField("paid", value.isPaid());
jgen.writeEndObject();
}
}
Прежде чем добавить OrderSerializer JSON ответ для http://localhost:8080/orders/1
похоже:
{
"location": "TAKE_AWAY",
"status": "PAYMENT_EXPECTED",
"orderedDate": "2014-03-24T15:05:09.988+01:00",
"items": [
{
"name": "Java Chip",
"quantity": 1,
"milk": "SEMI",
"size": "LARGE",
"price": {
"currency": "EUR",
"value": 4.2
}
}
],
"_links": {
...
}
}
После добавления OrderSerializer JSON ответ для http://localhost:8080/orders/1
похоже
{
"content": {
"paid": false
},
"_links": {
...
}
}
Главное, что оплаченный атрибут заключен в другое содержимое объекта, являющееся атрибутом org.springframework.hateoas.Resource. Я ожидал ответа без этого атрибута:
{
"paid": false,
"_links": {
...
}
}
Я изучил код Джексона и обнаружил, что UnwrappingBeanSerializer может быть решением, которое я ищу. Посмотрев, как инициализировать UnwrappingBeanSerializer, я думаю, что этот сериализатор не предназначен для использования в подклассах для пользовательского использования.
Я хотел бы знать, является ли этот отклоняющийся формат json при использовании настраиваемого сериализатора нормальным поведением или ошибкой в Spring Data Rest. Любая помощь приветствуется.
4 ответа
Это не ошибка Spring Data Rest, это на самом деле нормальное поведение сериализатора Джексона. Всякий раз, когда вы используете аннотацию @JsonUnwrapped (как это делает поле содержимого ресурса) вместе с настраиваемым сериализатором, сериализатор Jackson будет явно записывать имя поля (в данном случае содержимое). Взгляните на UnwrappingBeanPropertyWriter для получения более подробной информации. В любом случае вы были на правильном пути, используя UnwrappingBeanSerializer, но настройки немного отличаются от обычной регистрации Serializer. Следующий пример должен исправить вашу проблему:
@Override
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
mapper.registerModule(new Module() {
@Override
public String getModuleName() {
return "my.module";
}
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if(beanDesc.getBeanClass().equals(Order.class)) {
return new UnwrappingOrderSerializer((BeanSerializerBase) serializer, NameTransformer.NOP);
}
return serializer;
}
});
}
});
}
public class UnwrappingOrderSerializer extends UnwrappingBeanSerializer {
public UnwrappingBarSerializer(BeanSerializerBase src, NameTransformer transformer) {
super(src, transformer);
}
@Override
public JsonSerializer<Object> unwrappingSerializer(NameTransformer transformer) {
return new UnwrappingOrderSerializer(this, transformer);
}
@Override
protected void serializeFields(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
Order order = (Order) bean;
jgen.writeStringField("paid", order.isPaid();
}
@Override
public boolean isUnwrappingSerializer() {
return true;
}
}
Проекция является одним из решений и имеет приоритет над одним методом JsonSerializer
Другой:
@Override
public boolean isUnwrappingSerializer() {
return true;
}
Тогда вы сможете опустить начало и конец объекта.
Найдите мой пост здесь.
Помимо вышеприведенного решения andreast00 - убедитесь, что также переопределяете другие конструкторы, а также методы..., иначе это может создать UnwrappingBeanSerializer по умолчанию в фоновом режиме и игнорировать ваш пользовательский код сериализации:
public UnwrappingOrderSerializer(UnwrappingBeanSerializer src, ObjectIdWriter objectIdWriter) {
super(src, objectIdWriter);
}
public UnwrappingOrderSerializer(UnwrappingBeanSerializer src, ObjectIdWriter objectIdWriter, Object filterId) {
super(src, objectIdWriter, filterId);
}
public UnwrappingOrderSerializer(UnwrappingBeanSerializer src, Set<String> toIgnore) {
super(src, toIgnore);
}
@Override
public BeanSerializerBase withObjectIdWriter(ObjectIdWriter objectIdWriter) {
return new UnwrappingOrderSerializer(this, objectIdWriter);
}
@Override
public BeanSerializerBase withFilterId(Object filterId) {
return new UnwrappingOrderSerializer(this, this._objectIdWriter, filterId);
}
@Override
protected BeanSerializerBase withIgnorals(Set<String> toIgnore) {
return new UnwrappingOrderSerializer(this, toIgnore);
}
Кроме того, в зависимости от того, происходит ли сериализация от объекта @JsonUnwrapped, как объекта в массиве или как отдельный объект, jsonGenerater.writeStartObject может потребоваться вызывать в зависимости от того, запущен объект или нет. Я использовал:
boolean writeStartEnd = !jsonGenerator.getOutputContext().inObject()
|| jsonGenerator.getOutputContext().getCurrentName() != null;
if (writeStartEnd) jsonGenerator.writeStartObject(entity);
...serialisation code...
if (writeStartEnd) {
jsonGenerator.writeEndObject();
}
У меня такая же проблема. Вместо того чтобы использовать Jackson Serializer, я использовал @Projecton и настроил свой вывод. Вы можете найти ссылку здесь