akshattandon / projectlombok

Automatically exported from code.google.com/p/projectlombok
0 stars 0 forks source link

Equals of instances of different, but inherited, classes #761

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Have two classes. One inherits from other (see bellow)
2. Use equals on them.

What is the expected output? What do you see instead?
Running sample code:
    public static void main(String[] args) {
        FragmentIdentification fi = new FragmentIdentification(7, 7);
        FragmentData fd = new FragmentData(fi);
        System.out.println(fi.equals(fd));

    }

prints false. I expect that it will return true, as fi instance is same as fd 
(except fields that fi does not have). I am not 100% sure if this is globally 
good idea (to be able to compare instance A with instance B, while instance B 
is an instance of class which extends instance A class), but my natural feeling 
is that it should work this way.

What version of the product are you using? On what operating system?
Lombok v1.14.6 "Branching Cobra", eclipse Luna on 64bit linux. (maven build, 
which should not affect running in eclipse is on version 1.12.6)

Please provide any additional information below.

FragmentIdentification.java:

@NoArgsConstructor
@AllArgsConstructor
@Data
public class FragmentIdentification {
    public int responseID;
    public int fragmentID;
}

FragmentData.java:

@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class FragmentData extends FragmentIdentification {
    @Getter
    @Setter
    public byte data[];

    public FragmentData(FragmentIdentification fi) {
        this.fragmentID = fi.fragmentID;
        this.responseID = fi.responseID;
    }

    @Override
    public String toString() {
        String d = "data=";
        if (data == null) {
            d += "null";
        } else {
            if (data.length > 5) {
                d += "[" + data[0] + "],";
                d += "[" + data[1] + "],";
                d += "[" + data[2] + "],";
                d += "[" + data[3] + "],";
                d += "[" + data[4] + "],";
                d += "[...]";
            } else {
                for (byte b : data) {
                    d += "[" + b + "],";
                }
            }
        }
        return "FragmentData(responseID=" + responseID + ";fragmentID=" + fragmentID + ";" + d + ")";
    } // end of method toString()
}

Original issue reported on code.google.com by i...@plaintext.sk on 16 Dec 2014 at 9:27

GoogleCodeExporter commented 9 years ago
A little bit extended testcase:

    public static void main(String[] args) {
        FragmentIdentification fi = new FragmentIdentification(7, 7);
        FragmentData fd = new FragmentData(fi);

        System.out.println("Expecting true: " + fi.equals(fd));
        fd.setData(new byte[] {1, 7, 8});
        System.out.println("Expecting true: " + fi.equals(fd));

        System.out.println("Expecting false: " + fd.equals(fi));
        fd.setData(null);
        System.out.println("Expecting false?true: " + fd.equals(fi));
    }

Now outputs:
Expecting true: false
Expecting true: false
Expecting false: false
Expecting false?true: false

When I do workaround by overriding equals method in FragmentIdentification 
class like this:

    @Override
    public boolean equals(Object o) {
        if (o instanceof FragmentIdentification) {
            FragmentIdentification fi = (FragmentIdentification) o;
            if (fi.getFragmentID() != this.getFragmentID()) {
                return false;
            }
            if (fi.getResponseID() != this.getResponseID()) {
                return false;
            }
            return true;
        }
        return false;
    }

result is IMHO correct:
Expecting true: true
Expecting true: true
Expecting false: false
Expecting false?true: false

PS: In last test line I think (again natural feeling) that it should be always 
false to be correct.

Original comment by i...@plaintext.sk on 16 Dec 2014 at 9:32

GoogleCodeExporter commented 9 years ago
Lombok already supports this, but the way you did it, it can't work: 1. The 
parent class knows nothing about the child and equals must be reflexive. 2. The 
child class has a new field which is compared by default too.

You need to use `@EqualsAndHashCode` in the superclass and possibly fool around 
with `canEqual`. See http://projectlombok.org/features/EqualsAndHashCode.html

Original comment by Maaarti...@gmail.com on 17 Dec 2014 at 8:53

GoogleCodeExporter commented 9 years ago
Ehm, for sake of equality (generally in algebra and also in java) you are 
right. I forgot that equality means reflexive, transitive and SYMMETRIC 
function :-/

So I need to make my own equals like method and use it instead of crippling 
generally used method (equals(o1, o2) in java collections and so on. Thanks for 
pointing it out for me. I will probably make some method 
equalsInFragmentIdentificationParent(o1, o2) method. Thanks again. Issue should 
be closed.

Original comment by i...@plaintext.sk on 19 Dec 2014 at 11:50

GoogleCodeExporter commented 9 years ago
Thanks for resolving this :-)

Original comment by r.spilker on 3 Jan 2015 at 4:29