Как создать метод постмаппинга весной, чтобы клиентам приходилось вводить только частичный объект вместо полного объекта? - PullRequest
0 голосов
/ 25 декабря 2018

Вот мое 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]
}

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

{
    "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, только когда клиент отправляет запрос post с телом, содержащим currentlyWatching.Теперь я могу, конечно, проверить поля и отобразить их вручную, но мой WatchList не так прост, как показано здесь.Имеет более 10 полей (не только currentlyWatching и completed).Я хочу, чтобы какой-то динамичный простой способ сделать это.Также ручной способ сделать это, вероятно, в любом случае не будет лучшей практикой проектирования.

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

1 Ответ

0 голосов
/ 25 декабря 2018

Вот один из подходов, который я нашел после поиска в Интернете.Вы можете использовать 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);

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

Для каждого поля в нашем 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, тогда мы пропускаем операцию копирования.Следовательно, при таком подходе, если пользователь отправляет частичный объект из почтальона (например), мы будем копировать только те поля, в которые пользователь все время помещал некоторые вещи, не меняя другие поля (которые уже имеют старое содержимое) в нашем pojo назначения..

...