mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-08-17 00:25:54 +00:00
docs: update service layer
This commit is contained in:
+167
-126
@@ -3,104 +3,78 @@ title: Service Layer
|
|||||||
category: Architectural
|
category: Architectural
|
||||||
language: en
|
language: en
|
||||||
tag:
|
tag:
|
||||||
- Data access
|
- API design
|
||||||
|
- Business
|
||||||
|
- Decoupling
|
||||||
|
- Enterprise patterns
|
||||||
|
- Layered architecture
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Also known as
|
||||||
|
|
||||||
|
* Application Facade
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
Service Layer is an abstraction over domain logic. It defines application's boundary with a layer of services that
|
Encapsulate business logic in a distinct layer to promote separation of concerns and to provide a well-defined API for the presentation layer.
|
||||||
establishes a set of available operations and coordinates the application's response in each operation.
|
|
||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Typically applications require different kinds of interfaces to the data they store and the logic they implement.
|
Real-world example
|
||||||
Despite their different purposes, these interfaces often need common interactions with the application to access and
|
|
||||||
manipulate its data and invoke its business logic. Encoding the logic of the interactions separately in each module
|
|
||||||
causes a lot of duplication. It's better to centralize building the business logic inside single Service Layer to avoid
|
|
||||||
these pitfalls.
|
|
||||||
|
|
||||||
Real world example
|
|
||||||
|
|
||||||
> We are writing an application that tracks wizards, spellbooks and spells. Wizards may have spellbooks and spellbooks
|
> Consider a large restaurant where orders are taken by waitstaff and then sent to different kitchen sections (e.g., grill, salad, dessert). Each section specializes in a part of the meal, but the waitstaff don't interact directly with the kitchen staff. Instead, all orders go through a head chef who coordinates the workflow. The head chef acts like the service layer, handling the business logic (order coordination) and providing a unified interface for the waitstaff (presentation layer) to interact with the kitchen (data access layer).
|
||||||
may have spells.
|
|
||||||
|
|
||||||
In plain words
|
In plain words
|
||||||
|
|
||||||
> Service Layer is an abstraction over application's business logic.
|
> A pattern that encapsulates business logic into a distinct layer to promote separation of concerns and provide a clear API for the presentation layer.
|
||||||
|
|
||||||
Wikipedia says
|
Wikipedia says
|
||||||
|
|
||||||
> Service layer is an architectural pattern, applied within the service-orientation design paradigm, which aims to
|
> Service layer is an architectural pattern, applied within the service-orientation design paradigm, which aims to organize the services, within a service inventory, into a set of logical layers. Services that are categorized into a particular layer share functionality. This helps to reduce the conceptual overhead related to managing the service inventory, as the services belonging to the same layer address a smaller set of activities.
|
||||||
organize the services, within a service inventory, into a set of logical layers. Services that are categorized into
|
|
||||||
a particular layer share functionality. This helps to reduce the conceptual overhead related to managing the service
|
|
||||||
inventory, as the services belonging to the same layer address a smaller set of activities.
|
|
||||||
|
|
||||||
**Programmatic Example**
|
**Programmatic Example**
|
||||||
|
|
||||||
The example application demonstrates interactions between a client `App` and a service `MagicService` that allows
|
The example application demonstrates interactions between a client `App` and a service `MagicService` that allows interaction between wizards, spellbooks and spells. The service is implemented with 3-layer architecture
|
||||||
interaction between wizards, spellbooks and spells. The service is implemented with 3-layer architecture
|
|
||||||
(entity, dao, service).
|
(entity, dao, service).
|
||||||
|
|
||||||
For this explanation we are looking at one vertical slice of the system. Let's start from the entity layer and look at
|
For this explanation we are looking at one vertical slice of the system. Let's start from the entity layer and look at `Wizard` class. Other entities not shown here are `Spellbook` and `Spell`.
|
||||||
`Wizard` class. Other entities not shown here are `Spellbook` and `Spell`.
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "WIZARD")
|
@Table(name = "WIZARD")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class Wizard extends BaseEntity {
|
public class Wizard extends BaseEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
@Column(name = "WIZARD_ID")
|
@Column(name = "WIZARD_ID")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@ManyToMany(cascade = CascadeType.ALL)
|
@ManyToMany(cascade = CascadeType.ALL)
|
||||||
private Set<Spellbook> spellbooks;
|
private Set<Spellbook> spellbooks;
|
||||||
|
|
||||||
public Wizard() {
|
public Wizard() {
|
||||||
spellbooks = new HashSet<>();
|
spellbooks = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wizard(String name) {
|
public Wizard(String name) {
|
||||||
this();
|
this();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
public void addSpellbook(Spellbook spellbook) {
|
||||||
return id;
|
spellbook.getWizards().add(this);
|
||||||
}
|
spellbooks.add(spellbook);
|
||||||
|
}
|
||||||
|
|
||||||
public void setId(Long id) {
|
@Override
|
||||||
this.id = id;
|
public String toString() {
|
||||||
}
|
return name;
|
||||||
|
}
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Spellbook> getSpellbooks() {
|
|
||||||
return spellbooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpellbooks(Set<Spellbook> spellbooks) {
|
|
||||||
this.spellbooks = spellbooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSpellbook(Spellbook spellbook) {
|
|
||||||
spellbook.getWizards().add(this);
|
|
||||||
spellbooks.add(spellbook);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -109,29 +83,29 @@ Above the entity layer we have DAOs. For `Wizard` the DAO layer looks as follows
|
|||||||
```java
|
```java
|
||||||
public interface WizardDao extends Dao<Wizard> {
|
public interface WizardDao extends Dao<Wizard> {
|
||||||
|
|
||||||
Wizard findByName(String name);
|
Wizard findByName(String name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WizardDaoImpl extends DaoBaseImpl<Wizard> implements WizardDao {
|
public class WizardDaoImpl extends DaoBaseImpl<Wizard> implements WizardDao {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wizard findByName(String name) {
|
public Wizard findByName(String name) {
|
||||||
Transaction tx = null;
|
Transaction tx = null;
|
||||||
Wizard result;
|
Wizard result;
|
||||||
try (var session = getSessionFactory().openSession()) {
|
try (var session = getSessionFactory().openSession()) {
|
||||||
tx = session.beginTransaction();
|
tx = session.beginTransaction();
|
||||||
var criteria = session.createCriteria(persistentClass);
|
var criteria = session.createCriteria(persistentClass);
|
||||||
criteria.add(Restrictions.eq("name", name));
|
criteria.add(Restrictions.eq("name", name));
|
||||||
result = (Wizard) criteria.uniqueResult();
|
result = (Wizard) criteria.uniqueResult();
|
||||||
tx.commit();
|
tx.commit();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (tx != null) {
|
if (tx != null) {
|
||||||
tx.rollback();
|
tx.rollback();
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -140,56 +114,56 @@ Next we can look at the Service Layer, which in our case consists of a single `M
|
|||||||
```java
|
```java
|
||||||
public interface MagicService {
|
public interface MagicService {
|
||||||
|
|
||||||
List<Wizard> findAllWizards();
|
List<Wizard> findAllWizards();
|
||||||
|
|
||||||
List<Spellbook> findAllSpellbooks();
|
List<Spellbook> findAllSpellbooks();
|
||||||
|
|
||||||
List<Spell> findAllSpells();
|
List<Spell> findAllSpells();
|
||||||
|
|
||||||
List<Wizard> findWizardsWithSpellbook(String name);
|
List<Wizard> findWizardsWithSpellbook(String name);
|
||||||
|
|
||||||
List<Wizard> findWizardsWithSpell(String name);
|
List<Wizard> findWizardsWithSpell(String name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MagicServiceImpl implements MagicService {
|
public class MagicServiceImpl implements MagicService {
|
||||||
|
|
||||||
private final WizardDao wizardDao;
|
private final WizardDao wizardDao;
|
||||||
private final SpellbookDao spellbookDao;
|
private final SpellbookDao spellbookDao;
|
||||||
private final SpellDao spellDao;
|
private final SpellDao spellDao;
|
||||||
|
|
||||||
public MagicServiceImpl(WizardDao wizardDao, SpellbookDao spellbookDao, SpellDao spellDao) {
|
public MagicServiceImpl(WizardDao wizardDao, SpellbookDao spellbookDao, SpellDao spellDao) {
|
||||||
this.wizardDao = wizardDao;
|
this.wizardDao = wizardDao;
|
||||||
this.spellbookDao = spellbookDao;
|
this.spellbookDao = spellbookDao;
|
||||||
this.spellDao = spellDao;
|
this.spellDao = spellDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Wizard> findAllWizards() {
|
public List<Wizard> findAllWizards() {
|
||||||
return wizardDao.findAll();
|
return wizardDao.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Spellbook> findAllSpellbooks() {
|
public List<Spellbook> findAllSpellbooks() {
|
||||||
return spellbookDao.findAll();
|
return spellbookDao.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Spell> findAllSpells() {
|
public List<Spell> findAllSpells() {
|
||||||
return spellDao.findAll();
|
return spellDao.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Wizard> findWizardsWithSpellbook(String name) {
|
public List<Wizard> findWizardsWithSpellbook(String name) {
|
||||||
var spellbook = spellbookDao.findByName(name);
|
var spellbook = spellbookDao.findByName(name);
|
||||||
return new ArrayList<>(spellbook.getWizards());
|
return new ArrayList<>(spellbook.getWizards());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Wizard> findWizardsWithSpell(String name) {
|
public List<Wizard> findWizardsWithSpell(String name) {
|
||||||
var spell = spellDao.findByName(name);
|
var spell = spellDao.findByName(name);
|
||||||
var spellbook = spell.getSpellbook();
|
var spellbook = spell.getSpellbook();
|
||||||
return new ArrayList<>(spellbook.getWizards());
|
return new ArrayList<>(spellbook.getWizards());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -211,17 +185,84 @@ And finally we can show how the client `App` interacts with `MagicService` in th
|
|||||||
wizardsWithSpell.forEach(w -> LOGGER.info("{} has 'Fireball'", w.getName()));
|
wizardsWithSpell.forEach(w -> LOGGER.info("{} has 'Fireball'", w.getName()));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The program output:
|
||||||
|
|
||||||
|
```
|
||||||
|
INFO [2024-05-20 10:00:24,548] com.iluwatar.servicelayer.app.App: Enumerating all wizards
|
||||||
|
INFO [2024-05-20 10:00:24,550] com.iluwatar.servicelayer.app.App: Aderlard Boud
|
||||||
|
INFO [2024-05-20 10:00:24,550] com.iluwatar.servicelayer.app.App: Anaxis Bajraktari
|
||||||
|
INFO [2024-05-20 10:00:24,551] com.iluwatar.servicelayer.app.App: Xuban Munoa
|
||||||
|
INFO [2024-05-20 10:00:24,551] com.iluwatar.servicelayer.app.App: Blasius Dehooge
|
||||||
|
INFO [2024-05-20 10:00:24,551] com.iluwatar.servicelayer.app.App: Enumerating all spellbooks
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Orgymon
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Aras
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Kritior
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Tamaex
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Idores
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Opaen
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Book of Kihione
|
||||||
|
INFO [2024-05-20 10:00:24,554] com.iluwatar.servicelayer.app.App: Enumerating all spells
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Ice dart
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Invisibility
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Stun bolt
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Confusion
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Darkness
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Fireball
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Enchant weapon
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Rock armour
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Light
|
||||||
|
INFO [2024-05-20 10:00:24,558] com.iluwatar.servicelayer.app.App: Bee swarm
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Haste
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Levitation
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Magic lock
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Summon hell bat
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Water walking
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Magic storm
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Entangle
|
||||||
|
INFO [2024-05-20 10:00:24,559] com.iluwatar.servicelayer.app.App: Find wizards with spellbook 'Book of Idores'
|
||||||
|
INFO [2024-05-20 10:00:24,560] com.iluwatar.servicelayer.app.App: Xuban Munoa has 'Book of Idores'
|
||||||
|
INFO [2024-05-20 10:00:24,560] com.iluwatar.servicelayer.app.App: Find wizards with spell 'Fireball'
|
||||||
|
INFO [2024-05-20 10:00:24,562] com.iluwatar.servicelayer.app.App: Aderlard Boud has 'Fireball'
|
||||||
|
```
|
||||||
|
|
||||||
## Class diagram
|
## Class diagram
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
Use the Service Layer pattern when
|
|
||||||
|
|
||||||
* You want to encapsulate domain logic under API
|
* Use when you need to separate business logic from presentation logic.
|
||||||
* You need to implement multiple interfaces with common logic and data
|
* Ideal for applications with complex business rules and workflows.
|
||||||
|
* Suitable for projects requiring a clear API for the presentation layer.
|
||||||
|
|
||||||
|
## Known Uses
|
||||||
|
|
||||||
|
* Java EE applications where Enterprise JavaBeans (EJB) are used to implement the service layer.
|
||||||
|
* Spring Framework applications using the @Service annotation to denote service layer classes.
|
||||||
|
* Web applications that need to separate business logic from controller logic.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
Benefits:
|
||||||
|
|
||||||
|
* Promotes code reuse by encapsulating business logic in one place.
|
||||||
|
* Enhances testability by isolating business logic.
|
||||||
|
* Improves maintainability and flexibility of the application.
|
||||||
|
|
||||||
|
Trade-offs:
|
||||||
|
|
||||||
|
* May introduce additional complexity by adding another layer to the application.
|
||||||
|
* Can result in performance overhead due to the extra layer of abstraction.
|
||||||
|
|
||||||
|
## Related Patterns
|
||||||
|
|
||||||
|
* [Facade](https://java-design-patterns.com/patterns/facade/): Simplifies interactions with complex subsystems by providing a unified interface.
|
||||||
|
* [DAO (Data Access Object)](https://java-design-patterns.com/patterns/dao/): Often used together with the Service Layer to handle data persistence.
|
||||||
|
* [MVC (Model-View-Controller)](https://java-design-patterns.com/patterns/model-view-controller/): The Service Layer can be used to encapsulate business logic in the model component.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
* [Core J2EE Patterns: Best Practices and Design Strategies](https://amzn.to/4cAbDap)
|
||||||
|
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
|
||||||
|
* [Spring in Action](https://amzn.to/4asnpSG)
|
||||||
* [Martin Fowler - Service Layer](http://martinfowler.com/eaaCatalog/serviceLayer.html)
|
* [Martin Fowler - Service Layer](http://martinfowler.com/eaaCatalog/serviceLayer.html)
|
||||||
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a)
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public abstract class DaoBaseImpl<E extends BaseEntity> implements Dao<E> {
|
|||||||
@Override
|
@Override
|
||||||
public E merge(E entity) {
|
public E merge(E entity) {
|
||||||
Transaction tx = null;
|
Transaction tx = null;
|
||||||
E result = null;
|
E result;
|
||||||
try (var session = getSessionFactory().openSession()) {
|
try (var session = getSessionFactory().openSession()) {
|
||||||
tx = session.beginTransaction();
|
tx = session.beginTransaction();
|
||||||
result = (E) session.merge(entity);
|
result = (E) session.merge(entity);
|
||||||
|
|||||||
@@ -33,12 +33,16 @@ import javax.persistence.Id;
|
|||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spell entity.
|
* Spell entity.
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "SPELL")
|
@Table(name = "SPELL")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class Spell extends BaseEntity {
|
public class Spell extends BaseEntity {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
@@ -60,30 +64,6 @@ public class Spell extends BaseEntity {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Spellbook getSpellbook() {
|
|
||||||
return spellbook;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpellbook(Spellbook spellbook) {
|
|
||||||
this.spellbook = spellbook;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name;
|
return name;
|
||||||
|
|||||||
@@ -38,12 +38,16 @@ import javax.persistence.Id;
|
|||||||
import javax.persistence.ManyToMany;
|
import javax.persistence.ManyToMany;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spellbook entity.
|
* Spellbook entity.
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "SPELLBOOK")
|
@Table(name = "SPELLBOOK")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class Spellbook extends BaseEntity {
|
public class Spellbook extends BaseEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@@ -69,38 +73,6 @@ public class Spellbook extends BaseEntity {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Wizard> getWizards() {
|
|
||||||
return wizards;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWizards(Set<Wizard> wizards) {
|
|
||||||
this.wizards = wizards;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Spell> getSpells() {
|
|
||||||
return spells;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpells(Set<Spell> spells) {
|
|
||||||
this.spells = spells;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSpell(Spell spell) {
|
public void addSpell(Spell spell) {
|
||||||
spell.setSpellbook(this);
|
spell.setSpellbook(this);
|
||||||
spells.add(spell);
|
spells.add(spell);
|
||||||
|
|||||||
@@ -35,12 +35,16 @@ import javax.persistence.GeneratedValue;
|
|||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.ManyToMany;
|
import javax.persistence.ManyToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wizard entity.
|
* Wizard entity.
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "WIZARD")
|
@Table(name = "WIZARD")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class Wizard extends BaseEntity {
|
public class Wizard extends BaseEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@@ -62,30 +66,6 @@ public class Wizard extends BaseEntity {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Spellbook> getSpellbooks() {
|
|
||||||
return spellbooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpellbooks(Set<Spellbook> spellbooks) {
|
|
||||||
this.spellbooks = spellbooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSpellbook(Spellbook spellbook) {
|
public void addSpellbook(Spellbook spellbook) {
|
||||||
spellbook.getWizards().add(this);
|
spellbook.getWizards().add(this);
|
||||||
spellbooks.add(spellbook);
|
spellbooks.add(spellbook);
|
||||||
|
|||||||
+1
-1
@@ -122,7 +122,7 @@ class MagicServiceImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFindWizardsWithSpell() throws Exception {
|
void testFindWizardsWithSpell() {
|
||||||
final var wizards = Set.of(
|
final var wizards = Set.of(
|
||||||
mock(Wizard.class),
|
mock(Wizard.class),
|
||||||
mock(Wizard.class),
|
mock(Wizard.class),
|
||||||
|
|||||||
Reference in New Issue
Block a user