From: Ian R. <ian...@gm...> - 2009-10-04 18:25:24
|
I've been thinking some more about equals and inheritance; things are not quite as simple as they seem. The strategy on trunk currently is (in part): - If other has the same class as instance, proceed. - Else, if other's class is a proper subclass of instance's class, then call other.equals(instance) - Else, if other is a subclass of the most specific class contributing equals properties to instance, then proceed. - Else, return false. There is a problem with this, exposed in the most recent unit test commit to trunk. Suppose that Child1 and Child2 are subclasses of Parent. Child1 contributes no new properties, but Child2 does. In this case, if instance is of class Child1 and other of class Child2, the algorithm will consider them candidates for equality. However, if instance is of class Child2 and other of class Child1, then they are not considered equal, thus breaking symmetry. The solution that's been considered for this is to modify the above algorithm in the case where other is not a proper subclass of instance to check the most specific contributing class for both equals and other, based on the assumption that both are strictly relying on Pojomatic, by means of looking at their respective pojomators. This runs afoul of interfaces, however; if Intf is a pojomated interface, then implementing classes will not have a pojomator. One solution is to change the rules for interface pojomators. I think a more general solution might be to make this user selectable, with defaults determined by whether the pojomated class is an interface or not. Specifically, I'm proposing adding a new class-level annotation, say, @InheritanceStrategy. It's value would by typed to an InheritanceStrategy enum with three values: SUBCLASSABLE, NOT_SUBCLASSABLE and DEFAULT; DEFAULT would map to SUBCLASSABLE for non-interfaces and NOT_SUBCLASSABLE for interfaces. Additionally, it would be useful to add a no-arg annotation, say, @NotEqualToParent, to handle cases where the child knows that it cannot be considered equal to the parent. This would be useful for at least two cases I can think of. One is where a child class is semantically distinct from it's parent, even if there are no new properties (the difference might lie in method implementations). A second would be where a child class needs to introduce custom equals logic that cannot be expressed via pojomatic. The impact of this annotation would be to ensure that ClassProperties getEqualsParentClass would return a class no higher in the hierarchy than the annotated class. Thoughts? |