Другой вывод JSON при использовании пользовательского сериализатора json в Spring Data Rest

После добавления пользовательского сериализатора Jackson на основе официальная документация Я наблюдал немного другой формат вывода json.

Этот пример основан на spring-restbucks.

Расширение 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. Любая помощь приветствуется.


person ksokol    schedule 24.03.2014    source источник


Ответы (4)


Это не ошибка Spring Data Rest, это нормальное поведение сериализатора Jackson. Всякий раз, когда вы используете аннотацию @JsonUnwrapped (как это делает поле содержимого ресурса) вместе с пользовательским сериализатором, сериализатор Джексона будет явно записывать имя поля (в данном случае содержимое). Взгляните на 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;
    }
}
person andreast00    schedule 14.03.2015
comment
Спасибо за Ваш ответ. Он работает так, как ожидалось. В вашем примере есть ошибка компиляции в jgen.writeStringField("paid", order.isPaid();. Вы пропустили закрывающую скобку. - person ksokol; 23.03.2015
comment
Я получаю сообщение об ошибке: ``` Вызвано: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании bean-компонента с именем 'com.in.e.i18n.TranslationSerializer': неудовлетворенная зависимость, выраженная через параметр конструктора 0; вложенным исключением является org.springframework.beans.factory.NoSuchBeanDefinitionException: нет подходящего bean-компонента типа «com.fasterxml.jackson.databind.ser.std.BeanSerializerBase»: ожидается по крайней мере 1 bean-компонент, который квалифицируется как кандидат на автоматическое подключение. Аннотации зависимостей: {} ``` Есть идеи? - person Bruno Leite; 06.06.2017

Проекция — это одно решение, а переопределение одного метода JsonSerializer — другое:

    @Override
    public boolean isUnwrappingSerializer() {
        return true;
    }

Тогда вы сможете опустить начало и конец объекта.

Найдите мой пост в блоге здесь.

person Michael Simons    schedule 22.12.2017

Помимо приведенного выше решения andreast00, обязательно переопределите другие конструкторы и методы with..., иначе он может создать 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();
}
person Casey    schedule 12.10.2017
comment
У вас есть немного содержания там. Просто измените формулировку, например: за другим ответом на... например. В противном случае люди скоро отметят это как не ответ и, вероятно, понизят его. Используйте ответы вместо ответов! - person GhostCat; 12.10.2017

У меня такая же проблема. Вместо использования Jackson Serializer я использовал @Projecton и настроил свой вывод. Вы можете найти ссылку здесь

person Randika Hapugoda    schedule 03.01.2015