Java – Is a DTO Class Having an ArrayList of Its Own Type Good Design?

class-designcode-qualityjavaobject-oriented-designprogramming practices

I came across a DTO class like the below one.

class PersonDTO {
   private String firstName;
   private String middleName;
   private String lastName;
   private String dob;

   // some 50 fields more
   private List<PersonDTO> persons;

   //getters and setter
}

Question 1: Is it a good practice to have such huge DTO classes with so many properties?

Question 2: Is it a good practice to have a DTO class having an ArrayList of its own type? Wouldn't it cause a circular reference?

Update:

I work for a product in Healthcare domain. The use case is to generate a report of all the users in the system. Along with the list of users, the report also needs to show the summary information. The data need to be serialized, because the UI is expecting a JSON response.

Below is the actual DTO I was taking about.

A method was written in DAO class, which returns a UserDTO object.
This UserDTO object that is being returned.. consists of a List of all users, and some summary information like: total doctors, total nurses etc.

class UserDTO{
    private String userID; //This is unique

    private String firstName;
    private String middleName;
    private String lastName;
    private String dob;

    private String userType; // value can be DT(for doctor), ST(for nurse), 

    private int totalDoctorCount; //Holds the total number of UserDTOs with userType value set to DT in the ArrayList of users.

    private int totalNurseCount; //Holds the total number of UserDTOs with userType value set to ST in the ArrayList of users.


    // there are some 40 more properties.

    private List<UserDTO> users;

        //In this class there are also properties like below... 

        private String primaryAddrStreetName;
        private String primaryAddrCity;
        private String primaryAddrState;
        private String primaryAddrCountry;
        private String primaryAddrZipcode;

        private String billingAddrStreetName;
        private String billingAddrCity;
        private String billingAddrState;
        private String billingAddrCountry;
        private String billingAddrZipcode;

        private String shippingAddrStreetName;
        private String shippingAddrCity;
        private String shippingAddrState;
        private String shippingAddrCountry;
        private String shippingAddrZipcode;
}

Question 3: Is this DTO design apt for that use case? if not, then what would you suggest?

Question 4: The user has multiple addresses. But, Shouldn't the address details be in its own class (something like UserAddressDTO) and then we should add an array/ArrayList of UserAddressDTO in UserDTO??

Question 5: Also please give some insight about how would such kind of DTOs effect the JVM memory. The report would fetch thousands of records.

Best Answer

Question 1: Huge DTO

The goal of a DTO is to transfer data between processes or layers so to reduce the number of method calls.

It is hence not shocking to have a huge list of fields in such a structure. The alternative is to implement the DTO with some more complex structure, such as for example a ResultSet (or a dataset in a non-jaa context), that groups together different entities into one object. The inconvenience is then that the building of such object and the accessing of its elements is more time consuming, that with your flat (and ugly, but efficient) structure.

FYI, here you'll find some benefits and liabilities of the DTO.

Question 2 (updated after your edit)**

Having a list of PersonDTO in the PersonDTO means that the DTO has a recursive structure (e.g. like a tree). So it's not just flat data of one Person, but in fact one Person and a group of related Persons. The data structure is recursive.

This doesn't imply a circular reference, but you are right, some extra care is needed. It all depends on the original data structure:

  1. If the original objects form a hierarchy (for example, a manager and his employees, some of them themselves managers having their own employees), there is no issue to create the DTO. Same if it's another form of acyclic graph.
  2. If the original objects form a graph with possible cycles (for example, a person and her friends), there is a risk of cycling for ever when building the DTO. You can use a cycle detection to prevent transfering several time the same object. However, doing so would mean losing some relations in the transfer. In this case this DTO would be a bad design.

Note also that a same Person could appears several time in the DTO, in different lists (e.g. a part-time employee working for two departments). Unfortunately, during the data transfer, if the objects get deserialized to be transferred over the net and then serialized again, the object's identity (that you have in java with the same reference) might get lost, and you'll end up with two different objects replicating the same data. On the reception side, you'd therefore need to take some extra care as well : you have to decide if you'd detect such identity of objects or if you assume that all persons will always be different.

Conclusion: this structure could be ok, but it requires some information about the original domain objects to confirm.

Alternative: A much safer DTO structure would be to give each person an id, and organise the DTO as a collection of persons with their id. The list of PersonDTO could then be replaced with a list of ids. This is much more flexible, because it would work for all the types of person graphs and without need for any identity detection.

Question 3 and your last edit

If the goal of this DTO structure is only to provide a list of unrelated users, it should have the structure:

class UserDTO {             // Only properties of a single user
    private String userID; 
    private String firstName;
    ...
    private String userType;  
};
class UserListDTO {         // Only properties of the list as a whole
    private int totalDoctorCount; 
    ...
    private List<UserDTO> users;
};

As you see, a proper DTO design is often related to a multiplication of DTO classes. This is a well known topic as you can verify in the drawbacks exposed in this article here.

Inflating a unique DTO to combine the two layers into a single class is a shortcut that does not comply with the principle of single responsibility. Its also ambiguous: should the top user be added to the group or not ? Is he then counted in the statistics ? Shall the users in the list always have an empty list ? Shall they they provide statistics on themselves ? What if one user in the list comes with unexpected users in his list ? All these questions and extra processing, just to avoid one additional class...

In this case, it is a bad design.

Related Topic