Returns
true if the given object is a node with the same content than this node.
For this method, the meaning of same content is defined as below:
- The given object is also a
Node.
- The list returned by
TreeTable#getColumns() is equals for both nodes.
- The objects returned by
#getValue(TableColumn) are equal for each column.
- The list returned by
#getChildren() is equals for both node.
The node returned by
#getParent() shall
not be taken in account.
It is necessary to ignore the parent for consistency with
DefaultTreeTable#clone()and for avoiding infinite recursivity when comparing the children.
A third reason is given in the purpose example below.
Purpose of this method: example with ISO metadata
Consider the following tree made of ISO 19115 metadata objects: a platform containing a list of instruments,
and an instrument containing a reference to the platform on which the instrument is installed. In this example,
nodes 2 and 4 contain a reference to the same
Platform instance, so we have a cyclic graph:
Node 1: |
org.apache.sis.metadata.iso.acquisition.DefaultAcquisitionInformation |
Node 2: |
└─org.apache.sis.metadata.iso.acquisition.DefaultPlatform |
Node 3: |
└─org.apache.sis.metadata.iso.acquisition.DefaultInstrument |
Node 4: |
└─org.apache.sis.metadata.iso.acquisition.DefaultPlatform (same instance than above) |
Node 5: |
└─etc… |
The
org.apache.sis.metadata.AbstractMetadata#asTreeTable() method gives a view in which each node
has its content fully generated from wrapped metadata object. Consequently a naive walk over the above tree
causes an infinite loop with
TreeTable generating nodes with identical content as we bounce between
Platform and
Instrument metadata objects. To break this loop, we need to know when the
content of a node (in this example, the wrapped metadata object) has already been visited.
The parent shall
not be taken in account since node 2 and 4 have different parents
despite having the same
Platform content.
In this use case, the
Node.equals(Object) implementation needs only to compare the wrapped
metadata (usually given by the
#getUserObject()) since the node content,
including the list of children, is fully determined by those metadata. An identity comparison
(with
==) is sufficient for the purpose of avoiding infinite recursivity.
Flexibility in implementations
The above list specifies minimal conditions that must be true when two nodes are considered equal.
Implementations should not relax those conditions, but are free to make them more restrictive.
In particular, many implementations will require that the two nodes are instances of the same class.
Some implementations may also perform identity comparisons (with the
== operator) between values
instead than using
Object#equals(Object). This flexibility means that even if all above conditions
are true, this is not a guarantee that this method will return
true.
It is okay to not override this method at all since the identity comparison inherited from
Object#equals(Object) is consistent with this method contract. Alternatively,
Nodeimplementations having a content fully determined by the wrapped
#getUserObject() need only the following implementation:
javapublic boolean equals(Object obj)
return (obj instanceof MyNode) && ((MyNode) obj).getUserObject() == getUserObject();
}
}
Implementation details may vary, for example in the way to compare
null user objects or by invoking
Object#equals(Object) instead than performing identity comparisons. Note however that since this
method purpose is to detect cyclic graphs (see above example), user objects should be compared with
equals(Object) only if their implementations are known to be safe against infinite recursivity.