Overview
In Java, if a class does not override the
equals
method provided by the standard
java.lang.Object
type, then the class effectively has
reference equality.
That is, the
equals method simply compares
the addresses of the operands. In some cases this is desirable; in most
cases it is not. It is very easy to forget to override an
equals method, leading to extremely
subtle and dangerous bugs.
The com.io7m.jequality package
provides a set of annotations and a validator to check that classes
conform to their annotations. Essentially, the programmer annotates a
class with an annotation that states that the class is expected to
implement either structural or
reference equality. A class is assumed
to implement structural equality iff
it overrides equals. The provided
validator checks that classes are annotated, and that they implement
the type of equality that their annotations claim. As an extra safety
check, the validator checks that if equals
is overridden, then hashCode is
also overridden in the same class. The validator is not capable of checking that an
overridden equals actually does
implement structural equality (and does not,
for example, simply delegate to java.lang.Object).
Solving this problem is undecidable in general.
Validation
Validation of classes is expected to occur in the test suite of
the project using the com.io7m.jequality package.
The
RefEquality class uses the
EqualityReference
annotation to indicate that that it implements reference equality.
The validator checks that this is indeed the case. The following
test fails:
The RefEqualityWrong class claims that
it implements reference equality, and yet overrides
equals. The validator will catch
this and the test will fail.
The StructuralEquality class claims
to implement structural equality and does appear to override
equals (even though the equality
relation it defines is not correct). The validator assumes that this
class is correct.