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 AgreementRoles 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 AgreementRoles 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 scalarreferenceproperty. As theAgreementis 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 scalarreferenceproperty. However, since thePartyis not yet in-memory, using thereferenceproperty triggers a database query to "rehydrate" thePartyinstance.
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.