Как создать метод постмаппинга весной, чтобы клиентам нужно было вводить только частичный объект, а не полный объект?

Вот мой pojo

// Removed getters, setters, constructors for brevity, Also don't worry about Movie pojo
@Document
public class WatchList {
    @Id
    private String _id;
    private List<Movie> currentlyWatching;
    private List<Movie> completed;
}

Теперь в моем контроллере отдыха у меня есть такой метод постмаппинга

// Here id is the id of watchList I want to update
@PostMapping("/{id}/update")
public void updateItem(@PathVariable String id, @RequestBody WatchList watchList){
    WatchList old = watchListRepo.findById(id).get();  
    // Now update old with contents from watchList. However only change those fields that are sent from @RequestBody. How to do this?
}

Итак, от почтальона я отправляю почтовый запрос на эту конечную точку (с изменением идентификатора, конечно) с таким телом

{
    "currentlyWatching" : [...some new stuff]
}

Однако в моем pojo WatchList old уже есть такие вещи:

{
    "currentlyWatching" : [...some old stuff],
    "completed" : [...some old stuff],
}

Теперь, когда этот метод будет выполнен, я хочу, чтобы мое pojo превратилось в это

{
    "currentlyWatching" : [...some new stuff], // so this gets updated from post request
    "completed" : [...some old stuff], // this stays the same since post request body did not contain this field called completed
}

Итак, я, по сути, хочу обновить поле currentlyWatching только тогда, когда клиент отправляет почтовый запрос с телом, содержащим currentlyWatching. Теперь я, конечно, могу проверить поля и сопоставить их вручную, но мой WatchList не так прост, как показано здесь. В нем более 10 полей (не только currentlyWatching и completed). Мне нужен какой-нибудь простой динамичный способ сделать это. Также ручной способ сделать это, вероятно, в любом случае не будет лучшей практикой проектирования.

Extra Info: Я использую spring data mongo, так что класс аннотации или репозитория @Document (расширяет MongoRepository) из банок mongo. Также, если это вообще имеет значение, pojo Movie - это еще одно pojo, которое имеет вложенные свойства. Однако мне нужен способ делать это динамически, поэтому Movie pojo может быть чем угодно. Следовательно, решение, которое мы здесь выясняем, должно работать для любой схемы pojo Movie. Я также слышал о чем-то под названием BeanAwareUtils, это что-то, что можно здесь использовать?

Если я понимаю, почему бы вам не проверить, что пользователь @RequestBody отправил "completed" : [...some old stuff], этот материал или нет? -А если не поправишь?

Deadpool 25.12.2018 00:59

Думаю, это был бы ручной способ сделать это. Я имею в виду, как я уже сказал, что, если у меня в моем WatchListpojo 100 полей? Есть ли способ автоматически проверять поля, отправленные пользователем, и обновлять их только в моем старом pojo? Должен быть способ сделать это Джексоном или, может быть, какая-то другая библиотека. С ручным способом, как вы сказали, мне потребовалось бы больше 100 строк или немного дополнительной магии с полиморфизмом, что сделало бы мое приложение более сложным. Спасибо

theprogrammer 25.12.2018 01:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот один из подходов, который я нашел после поиска в Интернете. Можно использовать BeanUtils. Вот зависимость от maven (обязательно проверяйте обновленную версию, когда используете ее).

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>

Теперь вам нужно создать еще один класс (className может быть любым) следующим образом:

public class NullAwareBeanArrayUtilsBean extends BeanUtilsBean {

    @Override
    public void copyProperty(Object dest, String name, Object value) throws IllegalAccessException, InvocationTargetException {
        if (value == null || (value instanceof List<?> && ((List<?>) value).size() <= 0))
            return;
        super.copyProperty(dest, name, value);
    }

}

И если вы хотите использовать его где-нибудь еще в своем коде, используйте его так:

BeanUtilsBean notNull = new NullAwareBeanArrayUtilsBean();
notNull.copyProperties(dest, original);

Объяснение

BeanUtils - это библиотека, в которой есть один метод для копирования свойств из одного pojo в другое pojo. У него есть метод copyProperties, который внутренне вызывает метод copyProperty. Здесь мы создали подкласс под названием NullAwareBeanArrayUtilsBean, который расширяет BeanUtilsBean, и мы предоставили индивидуальную функциональность одному из его методов под названием copyProperty.

Помните, что этот метод вызывается изнутри методом copyProperties. Вы можете попробовать записать в консоль name в этом методе copyProperty, чтобы увидеть, что name относится к полю each из вашего pojo.

Что мы делаем в настраиваемом переопределенном методе copyProperty?

Рассмотрим эту строку

BeanUtilsBean notNull = new NullAwareBeanArrayUtilsBean();
notNull.copyProperties(dest, original);

Здесь мы говорим, что хотим скопировать материал из pojo original в pojo dest.

Для каждого поля в нашем pojo copyProperties внутренне вызывает наш собственный переопределенный метод с именем copyProperty.

Рассмотрим первую строку метода copyProperty:

if (value == null || (value instanceof List<?> && ((List<?>) value).size() <= 0)) return;

Здесь мы проверяем, value is null или if value is a List и это list empty, тогда мы пропускаем операцию копирования. Следовательно, при таком подходе, если пользователь отправляет частичный объект от почтальона (например), мы будем копировать только те поля, в которые пользователь поместил некоторые данные, не изменяя при этом другие поля (которые уже имеют старое содержимое) в нашем месте назначения. .

Другие вопросы по теме