Spring Boot: Abstracting Repository and Service - java

I have a similar entities and I use the following approach and use a base class:
#MappedSuperclass
public abstract class Dining {
// constructors
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dining_gen")
private long id;
#Column(nullable = false)
private UUID groupUuid;
#Column(nullable = false)
private String name;
}
#Entity
#SequenceGenerator(...)
#Table(...)
public class Room extends Dining {
// constructors
}
#Entity
#SequenceGenerator(...)
#Table(...)
public class Point extends Dining {
// constructors
}
I also use a base DTO, Request, etc. for these classes. However, I am wondering until which level I should apply abstraction. Should I use a generic base repository (Dining) and extend to Room and Point repositories?
What about services? I use Interface and its implementations in my Spring Bot app. In this scene, should I create a base interface or should I also create base service implementation and extend to Room and Point services?
If there is a good example as a best or proper practice, could you suggest me pls?

Related

Abstract class inheritance in springboot

I am a bit confused in regards to abstract classes and help would be great.
I have a the following classes
public abstract class AbstractUser{
private String username;
private String password;
}
And then I have this class
#Entity
public class Company extends AbstractUser{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String company_name
}
Now when I launch the application and I check the h2-console, the table Company only has the id and company_name. not the abstract classes variables. Is there a way to make it so it gets all the variables?
thank you in advance
You can use #MappedSuperclass Jpa annotation on the AbstractUser, Also consider moving the id attribute to the abstract class.
#MappedSuperclass
public abstract class AbstractUser{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
}
To resolve this, you will need JPA annotation on your abstract class. This is not specific to Spring Boot, it's JPA thing.
You can apply #MappedSuperclass on your abstract class and that should resolve this issue. Find More: Inherit Super Class Properties

JPA Inheritance Two Or More Superclass

I made a research about Inheritance in JPA and resources that I found uses just one superclass for each entity. But there is not an example that uses 2 or more superclass.
What about this:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = “Abstract_One”)
public abstract class AbstractOne {
#Id
protected Long id;
…
}
#Entity(name = “A”)
#DiscriminatorValue(“A”)
public class A extends AbstractOne {
#Column
private int a;
…
}
#Entity(name = “B”)
#DiscriminatorValue(“B”)
public class B extends A {
#Column
private int b;
…
}
Is it possible to do that?
If it is possible, which Inheritance Strategy allows that and gives the best data consistency?
I can imagine only the following example
#MappedSuperclass
public class A
{
...
#Id
#Column(name = "RECID")
public Long getId()
...
}
#MappedSuperclass
public class B extends A
{
...
#Column(name = "COL1")
public String getColumn1()
...
}
#Entity(name="INH_TAB1")
public class C extends B
{
...
#Column(name = "COL2")
public String getColumn2()
...
}
Also at the excellent book "Java Persistence with Hibernate" by Bauer, King, Gregory I found the following plase what can be useful in the context of this question:
6.5 Mixing inheritance strategies
You can map an entire inheritance hierarchy with the TABLE_PER_CLASS,
SINGLE_TABLE, or JOINED strategy. You can’t mix them — for example, to switch from a
table-per-class hierarchy with a discriminator to a normalized table-per-subclass
strategy. Once you’ve made a decision for an inheritance strategy, you have to stick with it. This isn’t completely true, however. By using some tricks, you can switch
the mapping strategy for a particular subclass. For example, you can map a class
hierarchy to a single table, but, for a particular subclass, switch to a separate
table with a foreign key–mapping strategy, just as with table-per-subclass.
However, I can not imagine any real case when such complex inheritance hierarchy will be required/useful and also it can affect performance.

How to inherit from multiple base abstract classes in JPA

I faced a problem how I can create JPA entity which extends multiple base abstract classes (without creating additional table). I know there is an annotation #MappedSuperclass, but it gives an ability to create only one base class as soon as we use extends and multiple inheritance is not a Java feature.
For example, I have two bases:
#MappedSuperclass
public abstract class Authored {
#ManyToOne
private User user;
}
and
#MappedSuperclass
public abstract class Dated {
private String creationDate;
}
I expect that some of my models will extend only Authored, some -- only Dated, and some -- both.
Though it's only possible to write
#Entity
public class MyEntity extends Authored {
...
}
or
#Entity
public class MyEntity extends Dated {
...
}
Some discussions propose to inherit classes in line (e.g. Authored and AuthoredAndDated) but this seems too dirty, none of this bases logically can't extend another one.
ADDITION
I have to note that this style is supported in other frameworks like Django (due to multiple inheritance in python) so it's strange that JPA doesn't support it.
I am sorry to disappoint you, but there is no other solution than creating AuthoredAndDated as you suggested.
We faced in the same issue for our entities and went with the same procedure.
We have a
#MappedSuperclass
public class TimestampedObject {
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at")
private Date createdAt;
#UpdateTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_at")
private Date updatedAt;
}
and a
#MappedSuperclass
public class IdObject {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id", updatable = false, columnDefinition = "serial")
private Long id;
}
Thus we created a TimestampedIdObject for this purpose.
Edit:
If you find another suitable solution, it would be great if you could post it here, as we have the same issue...
You should use an #Embeddable / #Embedded for goal by replacing inheritance with composition.
First, do not use #MappedSuperClass, but use #Embeddable instead for your classes you want to share the attributes with:
#Embeddable
public class Authored {...}
#Embeddable
public class Dated {...}
In the next step your Entity should not inherit from Authored or Dated but instead get an attribute referencing them:
#Entity
public class MyEntity {
#Embedded
private Authored authored;
#Embedded
private Dated dated;
}
If you want to get behaviour out of this, where you can generically access without those new attributes, you would need to introduce an interface exposing the necessary methods.
For expample if MyEntity should be able to provide details on last updates and creation, you would introduce an interface Authorable which defines to methods to access the relevant data.
public interface Authorable { /* necessary methods */ }
MyEntity will implement this interface then:
#Entity
public class MyEntity implements Authorable {
/* previous content plus implemented mehtods from interface */
}

Best architectural choice to merge 2 Spring Data JPA repository classes

I am pretty new in Spring Data JPA and I have the following doubt about the best way to implement the following situation:
So basically I have the following 2 model classes:
Room (representing a room of an accomodation):
#Entity
#Table(name = "room")
public class Room implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "id_accomodation_fk", nullable = false)
private Accomodation accomodation;
#ManyToOne
#JoinColumn(name = "id_room_tipology_fk", nullable = false)
private RoomTipology roomTipology;
#Column(name = "room_number")
private String number;
#Column(name = "room_name")
private String name;
#Column(name = "room_description")
#Type(type="text")
private String description;
#Column(name = "max_people")
private Integer maxPeople;
#Column(name = "is_enabled")
private Boolean isEnabled;
public Room() {
}
// GETTER AND SETTER METHODS
}
And RoomTipology that represent a tipology of room (something like: single room, double bed room, etcetc):
#Entity
#Table(name = "room_tipology")
public class RoomTipology implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "tipology_name")
private String name;
#Column(name = "tipology_description")
private String description;
#Column(name = "time_stamp")
private Date timeStamp;
#OneToMany(mappedBy = "roomTipology")
private List<Room> rooms;
#OneToOne(mappedBy = "roomTipology")
private RoomRate roomRate;
// GETTER AND SETTER METHODS
}
Ok, using Spring Data JPA I will have 2 different repository classes (one for the Room entity class and another one for the RoomTipology entity class, something like this:
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public interface RoomDAO extends JpaRepository<Room, Long> {
//#Query("FROM Room WHERE accomodation = :id")
List<Room> findByAccomodation(Accomodation accomodation);
}
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public interface RoomTipologyDAO extends JpaRepository<RoomTipologyDAO , Long> {
// METHOD RELATED TO THE ACCESS TO ROOM TIPOLOGY ENTITIES
}
Ok, I have the following architectural doubt:
I have 2 little repositories classes that access to something that are semantically similar (the room concept and the room tipology concept are both related to the room).
Furthermore, as you can see in the code of the RoomTipology entity class there is the following field:
#OneToMany(mappedBy = "roomTipology")
private List<Room> rooms;
that is mapped by the #OneToMany annotation (because starting from a specific room tipology I want to access to all the room of this accomodation of this tipology: all the single bed room or all the double bed room and so on...).
So, following this architectural style, I will have the method that return the List associated to a room tipology into the RoomTipologyDAO repository class and not into the RoomTipology repository class..it works fine but it is semantically bad because I will have a method of RoomTipologyDAO that doesn't return something related to RoomTipology instance but a list of Room object.
Is it not nasty?
So what is the best way to create an architecture that uses Spring Data JPA in this case?
I can't not do something like:
public interface RoomDAO extends JpaRepository<Room, Long> extends JpaRepository<RoomTipology, Long> {
........................................................
........................................................
........................................................
}
because Java doesn't support multiple heredity, but I think that the best choice should obtain something like this.
Maybe can I create something like a RoomMetaDAO class that have the RoomDAO and the RoomTipologyDAO as field? Can it work?
What do you think could be the best architectural choice for my situation?
You are absolutely correct in being sceptical about this.
The mistake is to assume that you should have one repository per entity. Instead you should look into the concept of aggregate roots from domain driven design.
An aggregate root is an entity that is used to manipulate a bunch of entities that can only accessed and modified through the aggregate root.
You want one repository per such aggregate root, which would be in your case the Room.
This is explained in much more detail in this article by Oliver Gierke, lead of the Spring Data project.

Modeling Classes: hierarchy or attribute?

I have currently these 2 entities:
Titular and Familiar (Family/kin/relative).
Familiar [0..*]<------>[1] Titular
These 2 classes has commons attributes of a person (firstName, lastName, birthDate....) and they are 2 kind of Affiliate
I want to unify those in one super class (generalization) Person but what I can't figure out is I should make Titular and Familiar extend Person or add Person as attribute of them.
Person also has to exists by itself (cannot be abstract) and not all Persons are Affiliates
BUT! I also need a way to establish/handle commons behaviors for Titular and Familiar.
Person [1]<------>[0..*] Titular
Person [1]<------>[0..*] Familiar
Titular [1]<------>[0..*] Familiar
So the doubt is:
public class Titular extend Person
public class Familiar extend Person {
or
public class Titular implement Affiliate {
private Person person;
public class Familiar implement Affiliate {
private Titular t;
private Person person;
or (3rd thought)
public class Person {
public abstract class Affiliate {
protected Person person;
public class Titular extends Affiliate {
The way I see it, all Affiliates are persons too (or you have exceptions to this?)! So the right hierarchy is:
Person --- Affiliate --- Titular
\- Familiar
Now, as to inheriting or having a pointer... that is called composition v/s inheritance and there are good arguments for both. The main reasons for chosing composition are
Mutable or optional relationships: Say, the owner of a car can change or a car can have no owner. A cat can not stop to be an animal and be something else.
Different Public API: While more work, composition allows you to manually forward whatever API you want to expose from your internal pointer, hiding or changing things from the "parent" as you will.
In general, you'll find inheritance makes more sense when ClassA IS-A ClassB, so you would not expect that to change nor would you want both classes to present a different API. You'll see this recommendation everywhere and it seems to fit your example like a glove.
After a few test, I had decided for Composition over inheritance.
As one of tag is "JPA", this solution has to be mapped/annotated
..and none of the possible annotations suits
#Inheritance(strategy = InheritanceType.JOINED/SINGLE_TABLE/TABLE_PER_CLASS)
If Titular and Familiar extends from Person, the ORM required a "DTYPE" column in Person, which is useless for me because no matters in how many Titular or Familiar a Person can/will become in its life, it just must be ONE register of Person.
And being an Affiliate is a "concept" or behavior, which I need it to do some polymorphic tasks, it doesn't has any persistable attribute (FOR NOW!), I will make an Interface of it.
#Entity
public class Persona {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Entity
public class Titular implements Afiliado {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JoinColumn(nullable = false)
#ManyToOne(optional = false)
private Persona persona;
#Entity
public class Familiar implements Afiliado {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JoinColumn(nullable = false)
#ManyToOne(optional = false)
private Persona persona;
#ManyToOne
private Titular titular;
public interface Afiliado {
public String getNumero();
//trick but necessary
public Persona getPersona();
//another default Java 8 implementations..
}
Stated in verbose, we want the following behavior (If I understand you correctly):
Titular is a Person who supports the functionality of an Affiliate.
Familiar is a Person who supports the functionality of an Affiliate and is associated with a Titular.
After reading these two lines enough number of times, one possible solution that seems reasonable is:
public class Titular extends Person implements Affiliate {
public class Familiar extends Person implements Affiliate {
private Titular t;

Categories