How do you declare an abstract method so that the parameter type (class) is always the Children class?

13,037

You can achieve that using generics on the declaration of your method signature at the abstract class:

public abstract class ValidableDTO<T extends ValidableDTO> implements Serializable {
    public abstract boolean isValid();
    public abstract boolean equals(T compared);
}

public class MyDTO extends ValidableDTO<MyDTO> {

    @Override
    public boolean isValid() {
        ...
    }


    @Override
    public boolean equals(MyDTO compared) {
        return true; // Comparison
    }
}

[EDIT]

Summary of the comments discussion below:

Regarding Java coding style and principles, it would be more reasonable to override the default public boolean equals(Object other) method instead of using a generics construction to try to constrain the type of the parameter. The standard practice for equals(...) is to use the instaceof operator to check for parameter compatibility, perform a cast and use finer-grained comparisons at the level of the specific object structure. That's similar to the proposed alternative implementation in the original post.

 @Override
public boolean equals(Object other) {
    if (this == other) return true;
    if (other instanceof MyDTO) { 
        MyDTO otherDTO = (MyDTO) other; 
        return this.getValue().equals(otherDTO.getValue()); // mind null values
    } 
    return false; 
}

This approach has the additional value of making the class ready for use in a collection, which is a very common case for DTO classes (e.g. List<UserDTO>)

Share:
13,037
dominicbri7
Author by

dominicbri7

Fullstack Java &amp; Javascript (React, Node) software engineer for Pleo.io in Copenhagen, Denmark.

Updated on June 04, 2022

Comments

  • dominicbri7
    dominicbri7 about 2 years

    EDIT : see bottom

    First off I searched for an answer before asking this one, but as you can see with the title I have no idea how this is called and I will edit the question whenever I can. Please forgive me on this.

    I have the following abstract class :

    public abstract class ValidableDTO implements Serializable {
        public abstract boolean isValid();
        public abstract boolean equals(ValidableDTO compared);
        // EDIT : new solution
        public abstract <T extends ValidableDTO> boolean equals(T compared);
    }
    

    I'd like to get a similar implementation :

    public class MyDTO extends ValidableDTO {
    
        private String myValue; //With a getter and setter of course
    
        public MyDTO() {
            // ...
        }
    
        @Override
        public boolean isValid() {
            return true; // Validation
        }
    
    // __________ LOOK AT THE FOLLOWING PARAMETER TYPE __________­­
        @Override
        public boolean equals(MyDTO compared) {
            return true; // Comparison
        }
    }
    

    The closest I could get is

    @Override
    public boolean equals(ValidableDTO compared) {
        boolean isEqual = false;
    
        if (compared instanceof MyDTO) {
            isEqual = getValue().equals(compared.getValue());
        }
    
        return isEqual;
    }
    

    I tried using public abstract boolean equals(<? extends ValidableDTO> compared); but this doesn't work.

    Is that even possible (it should be IMO) ? Thank you for your time and ... I still don't know how to describe this in 1 sentence... (lol)

    Sincerely. - me

    One step closer, thanks to user : aps !

    the following works in the Abstract class definition (ValidableDTO)

    public abstract <T extends ValidableDTO> boolean equals(T compared);
    

    __BUT__

    the implementation in MyDTO still isn't fine and in the end, it's exactly the same as using my 'if instanceof' solution because ValidableDTO is an abstract class and HAS to be inherited.

    What it looks like for now using Aps' solution :

    public <T extends ValidableDTO> boolean equals(T compared) { ... }
    

    I still have to check if it's a MyDTO instance...

    ON A SIDE NOTE, google doesn't seem to know if "Validable" or "Validatable" are real words.. which one is correct?

  • dominicbri7
    dominicbri7 about 13 years
    Thanks for the answer, please read my comment on A Lee's answer
  • maasg
    maasg about 13 years
    @dominicbri7 regarding coding style, I would question the need of your abstract class to override (specialize) Object.equals(Object other). The general contract of equals requires you to check for equality based on the type of the other object. A typical implementation of equals(Object other) will use instanceof and look like the alternative you presented in your original question. Unless you have an appealing reason to put that in your abstract class, I'd drop it and keep things simple.
  • maasg
    maasg about 13 years
    @dominicbri7 giving one more though to the design, I'd certainly drop equals and unless you're implementing some common boilerplate code in ValidableDTO, I'd make it an interface instead of an abstract class. From a composability perspective, it makes sense that a class implementing ValidableDTO has a validate method. But how do I read equals there? ValidableAndComparableDTO? Just food for thoughts.
  • dominicbri7
    dominicbri7 about 13 years
    @maasg I wanted to make it so each and every implementation of ValidableDTO (eg: MyDTO) could compare itself to another instance of the same implementation (another MyDTO) because each implementation will need to be compared differently but always versus another instance of the same type. Plus you cannot compare it using == operator even if it's a simple wrapper. I guess if I ever need to compare them I'll just define it directly in the implementation instead of in the Abstract superclass since it doesn't seem to be possible
  • maasg
    maasg about 13 years
    @dominicbri7 in a typical usage pattern for a DTO, you will have collections of objects at some point. A List, Set or Map using <MyDTO> will require a correct implementation of Object.equals(). What I want to say is that you can kill 2 (angry)birds with one rock by implementing @override public boolean equals(Object other) { if (other instanceof MyDTO) { MyDTO otherDTO = (MyDTO) other; return this.getValue().equals(otherDTO.getValue())} return false; } // mind null values
  • dominicbri7
    dominicbri7 about 13 years
    @maasg Thinking about it, I agree with you and I think I will drop the equals method as I recently mentioned above. At first it was an interface (that extends Serializable), but since an interface cannot implement another, and that Java doesn't support multiple inheritance, I decided to make it an Abstract Class because I will be able to implement multiple interfaces if I ever need them, it also makes more sense to me if MyDTO extends (IS A) ValidableDTO. Thanks for the wise advice
  • maasg
    maasg about 13 years
    @dominicbri7 No prob. I've summarized the discussion as an edit in the answer for future reference. For the rest, you know what to do :-)
  • dominicbri7
    dominicbri7 almost 13 years
    Well I finally dropped the equals but yeah I did kind of the same thing elsewere, using if(instanceof) and casting. Chosen as answer, as yours COMBINED with the discussions here in the comments led me to my decision. Have a nice life! :) lol