Как стать автором
Обновить

Комментарии 22

Чуть менее, чем каждый раз , когда я начинал с дженерик контроллеров / сервисов / репозиториев / и тому подобное - спустя некоторое время то тут то там появлялись специфичные вещи, которые не укладывались в общий подход и приходилось их переделывать на нормальные…

Если посмотрите - сам контроллер у меня не параметризирован + есть возможность напрямую вызывать специфичные методы репозитория и настраивать маппинг. Попробуйте попользовать и жду фидбэка- что не получилось сделать

За использование в контроллере репозиториев и базюшных сущностей нужно бить по рукам железной линейкой. Работа со слоем данных должна быть только в сераисах.

  1. Все это очень проекто-специфично

  2. Никто не мешает отнаследоваться от BaseService и вызывать репозиторий оттуда

Когда я был джуном, мне казалось, что круд на дженериках - хорошая идея.

Сейчас четко вижу, что такой общий код для сеньера станет обременением - если появится какой-то новый кастом(захотим файлы грузить), то вносить изменение в общее ядро станет долго и дорого.

Если же компания нанимает армию джунов, то для их контроля может быть разумным применение таких ограничений общего фраемворка. Но тогда уж лучше пойти по применению какого-нибудь 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 - что это фреймворк чисто для маппинга. Мой интерфейс выводит его на уровень абстракции выше его задачи - для связки сервиса и контроллера.

Коммент ниже про кастомизацию еще посмотрите:)

Простите, рука дрогнула, был вопрос про сложность использования. Ответ такой:

  1. Сложно ли пользоваться Spring Data Jpa? Упрощает ли он работу?

  2. Смотрели ли вы внутрь него, как он реализован?

Я к тому, что для использования предложенного подхода вам нужно только делать код контроллера в конце статьи, что проще для понимания и использования, чем традиционный подход

@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 для обьектов одного и того же класса вполне норм. Это другое

Это не критика, за удобство JPA приходиться платить. Обычно не критично, но, как всегда, думаю есть особые случаи.

Чем текущее решение лучше/практичнее Spring Data REST?
Зачем выдумывать очередной велосипед, кроме как получение физического контроля над выполняемой логикой?

Spring Data REST - это вообще не про это
Это Hateoas, который генерит код на основе репозиториев. Там как раз невозможно ничего кастомизировать

А про что тогда 0_о? В данный момент вы делаете тоже самое что и указанный модуль. Поясните в чем же фундаментальные различия.

Вы не поняли статьи или сути Spring Data REST, я делаю все вручную, никаких автогенераций кода. НО без дублирования кода - композиция, наследование, стратегия и дженерики.

Я может не уловил сути. Если у нас простой CRUD с возможностью кастомизации, тогда чем к задаче не подходит Spring Data REST?

См ответ выше + у нас не простой CRUD- любые методы в репозиториях и контроллерах поддерживаются. Суть - не дублировать код на основе общих методов и маппинга.

Ну это не правда, там много чего кастомизируется. Логика спокойно наращивается, притом довольно чистым кодом т.к. завязана на события CRUD. + Если нужно как-то изменять представление сущностей, там вроде работает JPA Projections.

Исходя из примеров кода, я вижу что для любого не CRUD действия, нужно переопределять метод или создавать промежуточный сервис в цепочку запрос-ответ. Я имею в виду, что всё, что не заложено в "дженерик" реализацию, нужно всё равно писать, но если это не нужно, то как бы есть уже готовое решение (Data REST).

Да, это Hateoas и RESTFull, где не так удобны некоторые операции. Но если задача стоит уменьшить кодовую базу (дублирование) + время разработки, я думаю это валидный способ, воспользоваться существующим инструментом.

А если задача построить большой монолит, то как бы я предполагаю, что хороший архитектор подумает о разработчиках\коллегах и базовые одинаковые действия выведет в слой абстракции.
Всегда же приятнее, удобно добавлять фичи, а не страдать и рефакторить бесконечно или колупаться в копипастах с мыслями "Где же не переименовал\добавил\удалил что-то?".

Ну да, все верно- код выше как раз ближе всего к слою абстрации для большого монилита, можно вынести в модуль common. В Data REST кроме ресурсов на выходе делать маппинг на урове проекций очень муторно. И совсем некастомизируемо, например кэширование в сервисах или енкодинг пароля приходится чз приседания с Jackson делать. Используя абстракцию вы ничем не связаны- собственный биндинг, валидация, кэширование, настраиваемый маппинг и пр. фишки Spring, Mapstruct и просто Java кода.

Отличная статья.

Про кастомность пишут зря, или плохо реализуют solid. Возможность расширения никто не отменял. У меня ко всему прочему ещё и консьюмеры и продюсеры на брокерах идут на дженериках вполне норм вкупе с дженерик контроллерами. Даже базовые операции всегда можно расширить, используя переопределяемые препроцессинг и постпроцессинг. Очень многие плавают в ООП и solid, и оттого в их коде крайне редко увидишь дженерики.

Лайк за статью однозначно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории