The recommended timeline for the whole module is 2 weeks.
- Adjust your solution prepared in Spring core module to get rid of in-memory data source and use real DB.
- Add support of CRUD operations for Tag (similar to Instagram hashtags) as well.
- Support retrieval of author by news id.
- Support retrieval of tags by news id.
- Support retrieval of news by tag names, tag ids, author name, title, content (all params are optional and can be used in conjunction).
Your Spring core solution. Do not delete or move basic interfaces for repository
, service
and controller
layers:
com.mjc.school.repository.model.BaseEntity
com.mjc.school.repository.BaseRepository
com.mjc.school.service.BaseService
com.mjc.school.controller.BaseController
Use org.springframework.boot:spring-boot-starter-data-jpa
dependency for
your solution, but with only one restriction: it's prohibited to use CRUD repositories, because the main goal of
this module is to get familiar with JPA/ORM:
- Criteria API
- JPQL
- Native queries
org.springframework.boot:spring-boot-starter-data-jpa
dependency is provided to simplify DB related beans
configuration.
Domain objects are represented by the following diagram
and have the following requirements:
- All fields for News (except
authorId
) and Author are required. - News title field should have length from 5 to 30.
- News content field should have length from 5 to 255.
- News and Author createdDate, lastUpdatedDate fields should be in ISO 8601 format. Example: 2018-08-29T06:12:15.156. More discussion here: stackoverflow: how to get iso 8601 .
Instead of explicitly set values to
createdDate
,lastUpdatedDate
fields, you should pay attention to already existing audit mechanism provided by Spring and JPA).
- News authorId field should be mapped to the author datasource.
- Author name field should have length from 3 to 15.
- Tag name field should have length from 3 to 15.
- Tag and News should have many-to-many relationship.
The system should expose CRUD operations for News, Author and Tag from the main module in the root project:
-
Create News - fill only title, content, authorId, tag ids (optional) and return created news.
-
Create Author - fill only name and return created author.
-
Create Tag - fill only name and return created tag.
-
Get All News – return list of news.
-
Get All Authors – return list of authors.
-
Get All Tags – return list of tags.
-
Get News by id – return news by provided id.
-
Get Author by id – return author by provided id.
-
Get Tag by id – return tag by provided id.
-
Update News – update only title, content, authorId, tag ids (optional) by provided news id and return updated news.
-
Update Author – update only name by provided author id and return updated author.
-
Update Tag – update only name by provided tag id and return updated tag.
-
Delete News – delete news by provided news id and return boolean value.
-
Delete Author – delete author by provided author id and return boolean value. When deleting author you could choose 2 options:
- set
authorId
field for corresponding news tonull
. - remove corresponding news.
Instead of explicitly maintaining data consistency (deleting related entities together with the parent one manually), you should pay attention to the correct description of relationships between entities using JPA annotations:
@OneToOne
,@OneToMany
,@ManyToMany
or use foreign key constraints in sql scripts. - set
-
Delete Tag – delete tag by provided tag id and return boolean value.
-
Get Author by news id – return author by provided news id.
-
Get Tags by news id – return tags by provided news id.
-
Get News by tag names, tag ids, author name, title, content (all params are optional and can be used in conjunction) – return news by provided params.
As well as in the Spring Core module all returned and received data should be like DTO type.
It would be interesting to read about
LazyInitializationException
and reasons to use DTO pattern along with JPA.
The mapping between the dto
and the model (domain object)
should be done at the service layer using any library. For
example: Mapstruct, Modelmapper.
Validate all the input according to the rules described in DataSource. It can be done by directly implementing all validations in business logic code or declaratively, e.g. via custom annotations.
To support your custom annotations and perform validation outside of business logic code you can use e.g. Aspects.
- Cover service layer with JUnit tests.
- Code should be clean and should not contain any “developer-purpose” constructions.
- App should be designed and written with respect to OOD and SOLID principles.
- Clear layered structure should be used with responsibilities of each application layer defined.
- All business logic should be written in the module-service: mapping
model
todto
and vice versa, validation, etc. - Module-web and module-service should accept and return
dto
objects. - Module-repository should accept and return
model
objects. - Convenient error/exception should be implemented: all errors should be meaningful. Errors should
contain
errorMessage
anderrorCode
, whereerrorCode
is your custom code. - Application should be tested and pass all tests suites.
- Change archunit-junit dependency to archunit-junit5:
testImplementation "com.tngtech.archunit:archunit-junit5:1.0.0"
- Use javax
implementation "org.springframework.boot:spring-boot-starter-data-jpa:2.7.7"
. Exactly2.7.7
version, because older versions is jakarta.
- Java 17 should be used.
- Gradle. Multi-module project. Spring Boot.
- Application packages root:
com.mjc.school
. - Java Code Convention is mandatory.
If you have finished task and would like to see the original solution of it written by our experts, write in #stage-3 channel about it. Access will be provided.