
Комментарии 22
Чуть менее, чем каждый раз , когда я начинал с дженерик контроллеров / сервисов / репозиториев / и тому подобное - спустя некоторое время то тут то там появлялись специфичные вещи, которые не укладывались в общий подход и приходилось их переделывать на нормальные…
Если посмотрите - сам контроллер у меня не параметризирован + есть возможность напрямую вызывать специфичные методы репозитория и настраивать маппинг. Попробуйте попользовать и жду фидбэка- что не получилось сделать
Когда я был джуном, мне казалось, что круд на дженериках - хорошая идея.
Сейчас четко вижу, что такой общий код для сеньера станет обременением - если появится какой-то новый кастом(захотим файлы грузить), то вносить изменение в общее ядро станет долго и дорого.
Если же компания нанимает армию джунов, то для их контроля может быть разумным применение таких ограничений общего фраемворка. Но тогда уж лучше пойти по применению какого-нибудь jhipster.
Можно без проблем на этом базовом коде файлы грузить. Мы же ничем не ограничиваем контроллеры и сервисы. JHipster - я ее немного пробовал, она опять про автогенерацию, насколько знаю. + если совсем не вписывается - то просто BaseService для этого контроллера не использовать....
@Rion333 - еще такой вопрос-без учета BaseService (BaseTo, BaseMapper, BaseEntity, WebUtil) - тоже синьору повредит?
А как вы ответите на вопрос: почему spring еще не реализовал эти абстракции у себя, если это такая хорошая идея, и соответствует философии spring по устранению шаблонного кода? Вряд ли, они просто не додумались.
Я думаю ответ как раз в том - что текущий уровень абстракций инструментов оптимальный по соотношению функционал/гибкость.
Ну и для простых crud также spring data rest подойдёт.
Отвечу так: текущий уровень абстракции подходит под любой проект и любое решение. Далее никто вам не мешает кастомизировать его под себя.
Например в микросервисах BaseService скорее всего будет лишним.
Про BaseEntity - я в нем выбрал @Access(AccessType.FIELD), Lombook и OpenAPI. Естественно, что Spring Data не может это внести себе в зависимости. Он предоставляет выбор всем, далее - сделай, как ты это используешь.
По поводу Mapstruct - что это фреймворк чисто для маппинга. Мой интерфейс выводит его на уровень абстракции выше его задачи - для связки сервиса и контроллера.
Коммент ниже про кастомизацию еще посмотрите:)
Простите, рука дрогнула, был вопрос про сложность использования. Ответ такой:
Сложно ли пользоваться Spring Data Jpa? Упрощает ли он работу?
Смотрели ли вы внутрь него, как он реализован?
Я к тому, что для использования предложенного подхода вам нужно только делать код контроллера в конце статьи, что проще для понимания и использования, чем традиционный подход
@Override public final int hashCode() {
return getEffectiveClass(this).hashCode();
}
Выглядит сурово. У всех ентити одного типа будет один и тот же хешкод?
Да. По ссылке jpa buddy посмотрите
У себя на сайте они пишут, что с hashCode от ID будут проблемы, если сначала был NULL, а затем после сохранения появился ID, сгенерированный БД:
"Once the id is generated (on its first save) the hashCode gets changed. So the HashSet looks for the entity in a different bucket and cannot find it. It wouldn’t be an issue if the id was set during the entity object creation (e.g. was a UUID set by the app), but DB-generated ids are more common."
Понял, критика не к вам, извините :)
Особенно порадовало, что решение от Thorben Janssen им не подошло, т.к.
The implementation proposed by Thorben Janssen returns the same hash code for all objects! This approach makes
hashCode()completely meaningless.
А вот возвращать один и тот же hashCode для обьектов одного и того же класса вполне норм. Это другое
Чем текущее решение лучше/практичнее Spring Data REST?
Зачем выдумывать очередной велосипед, кроме как получение физического контроля над выполняемой логикой?
Spring Data REST - это вообще не про это
Это Hateoas, который генерит код на основе репозиториев. Там как раз невозможно ничего кастомизировать
Я может не уловил сути. Если у нас простой CRUD с возможностью кастомизации, тогда чем к задаче не подходит Spring Data REST?
См ответ выше + у нас не простой CRUD- любые методы в репозиториях и контроллерах поддерживаются. Суть - не дублировать код на основе общих методов и маппинга.
Ну это не правда, там много чего кастомизируется. Логика спокойно наращивается, притом довольно чистым кодом т.к. завязана на события CRUD. + Если нужно как-то изменять представление сущностей, там вроде работает JPA Projections.
Исходя из примеров кода, я вижу что для любого не CRUD действия, нужно переопределять метод или создавать промежуточный сервис в цепочку запрос-ответ. Я имею в виду, что всё, что не заложено в "дженерик" реализацию, нужно всё равно писать, но если это не нужно, то как бы есть уже готовое решение (Data REST).
Да, это Hateoas и RESTFull, где не так удобны некоторые операции. Но если задача стоит уменьшить кодовую базу (дублирование) + время разработки, я думаю это валидный способ, воспользоваться существующим инструментом.
А если задача построить большой монолит, то как бы я предполагаю, что хороший архитектор подумает о разработчиках\коллегах и базовые одинаковые действия выведет в слой абстракции.
Всегда же приятнее, удобно добавлять фичи, а не страдать и рефакторить бесконечно или колупаться в копипастах с мыслями "Где же не переименовал\добавил\удалил что-то?".
Ну да, все верно- код выше как раз ближе всего к слою абстрации для большого монилита, можно вынести в модуль common. В Data REST кроме ресурсов на выходе делать маппинг на урове проекций очень муторно. И совсем некастомизируемо, например кэширование в сервисах или енкодинг пароля приходится чз приседания с Jackson делать. Используя абстракцию вы ничем не связаны- собственный биндинг, валидация, кэширование, настраиваемый маппинг и пр. фишки Spring, Mapstruct и просто Java кода.
Отличная статья.
Про кастомность пишут зря, или плохо реализуют solid. Возможность расширения никто не отменял. У меня ко всему прочему ещё и консьюмеры и продюсеры на брокерах идут на дженериках вполне норм вкупе с дженерик контроллерами. Даже базовые операции всегда можно расширить, используя переопределяемые препроцессинг и постпроцессинг. Очень многие плавают в ООП и solid, и оттого в их коде крайне редко увидишь дженерики.
Лайк за статью однозначно.
Контроллеры на дженериках: пишем кода в 3 раза меньше