spring-bootoopdesign-patternsjava-8object-oriented-analysis

How to design classes in spring boot for 3 different roles?


I am working on an spring boot application which deals with distribution management. There are 3 types of user who will interact with the system - admin, distributor and retailer.

  1. There can be only one administrator of a company.
  2. There can be only one distributor in a city of a particular company.
  3. Retailer can be linked with with distributors of different companies of a specific city.

Now, for this stuff. I have created 5 classes - User, Role, Administrator, Distributor, and Retailer. Can please anyone suggest me that how should I approach this problem with respect to designing the required classes. I tried initially but still I am thinking that this classes structure is complex in itself. Is there something which I am missing out or is there any design pattern which can make things quite more understable ??

@Entity
@Table(name = "tbl_User")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "user_id")
    private Long userId;
    
    @NotNull(message = "first Name cannot be null")
    @Column(name = "first_Name")
    private String firstName;
    
    @NotNull(message = "last Name cannot be null")
    @Column(name = "last_Name")
    private String lastName;
    
    @ManyToOne()
    @JoinColumn(name = "role_Id")
    private Role role;
    
    @NotNull
    @Size(min = 10, max = 10, message = "Contact must be of 10 characters")
    @Column(name = "contact")
    private String contact;
    
    @NotNull
    @Email(message = "Email should be valid")
    @Column(name = "email", unique = true)
    private String email;
    
    @NotNull
    @Size(min = 10, max = 255, 
    message = "Local address must be between 10 and 255 characters")
    @Column(name = "local_Address")
    private String localAddress;
    
    @ManyToOne()
    @JoinColumn(name = "city_Id")
    private City city;
    
    @NotNull
    @Column(name = "user_Name")
    private String userName;
    
    @NotNull
    @Column(name = "password")
    private String password;
    
    @Column(name = "registered_On")
    private LocalDateTime registeredOn;
    
    @Column(name = "updated_On")
    private LocalDateTime updatedOn;
    
    @Column(name = "approved_By")
    private Long approvedBy;
    
    @NotNull
    @Size(min = 1, max = 1, 
    message = "Approval status must be of 1 character.")
    @Column(name = "approval_Status")
    private String approvalStatus;

    @NotNull
    @Column(name = "active_Status")
    private boolean activeStatus;
    
    @Transient 
    private Company company;
}
@Entity
@Table(name = "tbl_Administrator")
public class Admin {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int adminId;
    
    @OneToOne()
    @JoinColumn(name = "user_Id")
    private User user;
    
    @OneToOne()
    @JoinColumn(name = "company_Id")
    private Company company;    
}
@Entity
@Table(name = "tbl_Distributor")
public class Distributor {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long distributorId;
    
    @OneToOne()
    @JoinColumn(name = "user_Id")
    private User user;
    
    @ManyToOne()
    @JoinColumn(name = "company_Id")
    private Company company;
}
@Entity
@Table(name = "tbl_Retailer")
public class Retailer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long retailerId;

    @OneToOne()
    @JoinColumn(name = "user_Id")
    private User user;
}

Solution

  • I would go with a @MappedSuperclass instead of making User and entity itself. Basically, Admin, Distributor and Retailer would extend this mapped superclass. A separate table for each is created but no table is created for the superclass (User) itself.

    @MappedSuperclass
    public class User {
    
       // Your properties
       
    }
    
    @Entity
    @Table(name = "tbl_Administrator")
    public class Admin extends User {
    
        @OneToOne()
        @JoinColumn(name = "company_Id")
        private Company company;  
         
    }
    
    @Entity
    @Table(name = "tbl_Distributor")
    public class Distributor extends User {
        
        @ManyToOne()
        @JoinColumn(name = "company_Id")
        private Company company;
        
    }
    
    @Entity
    @Table(name = "tbl_Retailer")
    public class Retailer extends User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY) 
        private Long retailerId;
        
    }
    

    You have other possibilities (read more at https://medium.com/analytics-vidhya/jpa-hibernate-entity-inheritance-1f6aa7ea2eea), such as the following:

    Still, I would go with the Mapped Superclass one as described.