Пользовательский сериализатор Spring Boot для класса Collection - PullRequest
1 голос
/ 19 марта 2019

Я пытался реализовать собственный сериализатор для одного из свойств моего объекта, чтобы получить другую структуру JSON при возврате его из моего контроллера REST.

Мои ограничения: я не могу изменить интерфейс контроллера REST или классы модели (поэтому я не могу добавить дополнительную аннотацию и т. Д., Что могло бы сделать это проще). Единственное, о чем я мог подумать, делая его рендеринг отличным от описанного в модели, это пользовательский сериализатор, если есть более подходящие подходы, пожалуйста, не стесняйтесь, сообщите мне другой подход, который находится в пределах ограничений.

Мои модели выглядят примерно так:

public class WrapperModel {

  // a lot of autogenerated fields

  List<Property> properties;

  // getters/setters
}

public class Property {

  private String name;

  private String value;

  // getters / setters

}

Итак, когда это отображается, это выглядит так:

{   ....   
    "properties": [
      {"key1": "value1"}, {"key2": "value2"},...   
    ] 
}

Что бы я хотел, это:

{   ....   
    "properties": {
      "key1": "value1",
      "key2": "value2",
      ...  
    }
}

Сериализатор для этого достаточно прост:

public class PropertyListJSONSerializer extends StdSerializer<List<Property>> {

//....

@Override
public void serialize(List<Property> value, JsonGenerator gen,   SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    for(Property p: value){
        gen.writeStringField(p.getName(), p.getValue());
    }
    gen.writeEndObject();
}

}

Теперь, когда я пытаюсь зарегистрировать этот сериализатор внутри @Configuration файла:

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

    SimpleModule module = new SimpleModule();
    module.addSerializer(List<Property>.class, new PropertyListJSONSerializer());
    mapper.registerModule(module);

    return mapper;
}

это не работает, потому что List<Property>.class нельзя использовать для addSerializer, так как это шаблонный класс. Есть ли другой способ добавить этот сериализатор или что-то подобное?

Я не хочу добавлять пользовательский сериализатор для WrapperModel, так как этот класс генерируется автоматически, а поля можно добавлять и удалять. Это должно быть возможно без изменения кода приложения (если бы у меня был собственный сериализатор, вам нужно было бы также добавить / удалить поля из сериализатора (?)). Или есть способ использовать стандартный сериализатор для класса и просто вручную обработать это поле List<>.

Классы моделей генерируются генератором Openapi-кода Spring Boot, поэтому существует очень ограниченный набор аннотаций JSON, которые я могу поместить поверх полей модели (если есть способ аннотации, пожалуйста, не стесняйтесь публиковать, как я могу проверьте исходный код openapi, поддерживается ли эта конкретная аннотация). Но я бы предпочел использовать либо собственный сериализатор для List<Property>, если это вообще возможно, либо написать сериализатор для WrapperModel, который использует StdSerializer для всего и обрабатывает только свойство List самостоятельно.

1 Ответ

1 голос
/ 19 марта 2019

MixIn

В этом случае нам нужно использовать функцию MixIn.Создайте интерфейс, как показано ниже:

interface WrapperModelMixIn {

    @JsonSerialize(using = PropertyListJSONSerializer.class)
    List<Property> getProperties();
}

и зарегистрируйте его, как показано ниже:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(WrapperModel.class, WrapperModelMixIn.class);

Старое предложение

Вам необходимо использовать Jackson типы, которые позволяют зарегистрировать сериализатордля универсального типа.Ваш сериализатор после изменения может выглядеть следующим образом:

class PropertyListJSONSerializer extends StdSerializer<List<Property>> {

    public PropertyListJSONSerializer(JavaType type) {
        super(type);
    }

    @Override
    public void serialize(List<Property> value, JsonGenerator gen, SerializerProvider provider)
        throws IOException {
        gen.writeStartObject();
        for (Property p : value) {
            gen.writeStringField(p.getName(), p.getValue());
        }
        gen.writeEndObject();
    }
}

И вы можете зарегистрировать его, как показано ниже:

ObjectMapper mapper = new ObjectMapper();

CollectionType propertiesListType = mapper.getTypeFactory().constructCollectionType(List.class, Property.class);
SimpleModule module = new SimpleModule();
module.addSerializer(new PropertyListJSONSerializer(propertiesListType));
mapper.registerModule(module);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...