ObjectContracts
Provides fluent composition for Objects' equals, hashCode and toString.
API
class ObjectContracts {
ToString<T> toString(String name, Function<T, ?> getter)
Equality<T> checkEquals(Function<T, ?> getter)
Hashing<T> hashing(Function<T, ?> getter)
ObjectContract<T> contract(Class<T> objectClass)
ObjectContract<T> parse(Class<T> target, String propertyNames)
String toString(T obj, String propertyNames)
boolean equals(T obj, Object other, String propertyNames)
int hashCode(Object obj, String propertyNames)
int compare(T obj, T other, String propertyNames)
}
Example Usage
For example:
@RequiredArgsConstructor(staticName = "of")
public static class ComplexNumber implements Comparable<ComplexNumber> {
@Getter private final int real;
@Getter private final int imaginary;
private ObjectContracts.ObjectContract<ComplexNumber> contract
= ObjectContracts.contract(ComplexNumber.class)
.thenUse("real", ComplexNumber::getReal)
.thenUse("imaginary", ComplexNumber::getImaginary);
@Override
public boolean equals(Object o) {
return contract.equals(this, o);
}
@Override
public int hashCode() {
return contract.hashCode(this);
}
@Override
public int compareTo(final ComplexNumber other) {
return contract.compare(this, other);
}
@Override
public String toString() {
return contract.toString(this);
}
}
There are a number of deprecated methods that identify property names as strings. These should not be use, as they use are not type-safe and also use reflection heavily and so impose a performance hit. |
Usage Notes
Be aware of ORM loading issues
ObjectContracts
implementation can cause DataNucleus to recursively rehydrate a larger number of associated entities (More detail below).
We therefore recommend that you disable persistence-by-reachability by adding:
datanucleus.persistenceByReachabilityAtCommit=false
In the course of a transaction, the Agreement
entity is loaded into memory (not necessarily modified), and then new AgreementRole
s are associated to it.
All these entities implement Comparable
using ObjectContracts
, so that the implementation of AgreementRole
's (simplified) is:
public class AgreementRole {
...
public int compareTo(AgreementRole other) {
return ObjectContracts.compareTo(this, other, "agreement","startDate","party");
}
...
}
while Agreement
's is implemented as:
public class Agreement {
...
public int compareTo(Agreement other) {
return ObjectContracts.compareTo(this, other, "reference");
}
...
}
and Party
's is similarly implemented as:
public class Party {
...
public int compareTo(Party other) {
return ObjectContracts.compareTo(this, other, "reference");
}
...
}
DataNucleus’s persistence-by-reachability algorithm adds the AgreementRole
s into a SortedSet
, which causes AgreementRole#compareTo()
to fire:
-
the evaluation of the "agreement" property delegates back to the
Agreement
, whose ownAgreement#compareTo()
uses the scalarreference
property. As theAgreement
is already in-memory, this does not trigger any further database queries -
the evaluation of the "startDate" property is just a scalar property of the
AgreementRole
, so will already in-memory -
the evaluation of the "party" property delegates back to the
Party
, whose ownParty#compareTo()
requires the uses the scalarreference
property. However, since theParty
is not yet in-memory, using thereference
property triggers a database query to "rehydrate" theParty
instance.
In other words, figuring out whether AgreementRole
is comparable requires the persistence-by-reachability algorithm to run, causing the adjacent associated entity Party
to also be retrieved.