Skip to content

Commit 434f2bd

Browse files
committed
add hashcode/equals/compareto/tostring helpers for easier overriding
1 parent 6e2b4ed commit 434f2bd

File tree

1 file changed

+71
-14
lines changed

1 file changed

+71
-14
lines changed

src/main/java/org/omnifaces/persistence/model/BaseEntity.java

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@
1212
*/
1313
package org.omnifaces.persistence.model;
1414

15+
import static java.util.Arrays.stream;
16+
import static java.util.Comparator.comparing;
17+
import static java.util.Comparator.naturalOrder;
18+
import static java.util.Comparator.nullsLast;
19+
import static java.util.Objects.requireNonNullElseGet;
20+
1521
import java.io.Serializable;
22+
import java.util.Comparator;
1623
import java.util.Objects;
24+
import java.util.function.Function;
1725

1826
import jakarta.persistence.EntityListeners;
1927
import jakarta.persistence.MappedSuperclass;
@@ -49,39 +57,88 @@ public abstract class BaseEntity<I extends Comparable<I> & Serializable> impleme
4957
*/
5058
@Override
5159
public int hashCode() {
52-
return (getId() != null)
53-
? Objects.hash(getId())
54-
: super.hashCode();
60+
return hashCode(BaseEntity::getId);
61+
}
62+
63+
@SafeVarargs
64+
@SuppressWarnings("unchecked")
65+
protected final <E extends BaseEntity<I>> int hashCode(final Function<E, Object>... getters) {
66+
final var values = stream(getters).map(getter -> getter.apply((E) this)).filter(Objects::nonNull).toArray();
67+
return values.length > 0 ? Objects.hash(values) : super.hashCode();
5568
}
5669

5770
/**
5871
* Compares by default by entity class (proxies taken into account) and ID.
5972
*/
6073
@Override
61-
public boolean equals(Object other) {
62-
return (getId() != null && getClass().isInstance(other) && other.getClass().isInstance(this))
63-
? getId().equals(((BaseEntity<?>) other).getId())
64-
: (other == this);
74+
public boolean equals(final Object other) {
75+
return equals(other, BaseEntity::getId);
76+
}
77+
78+
@SafeVarargs
79+
@SuppressWarnings("unchecked")
80+
protected final <E extends BaseEntity<I>> boolean equals(final Object other, final Function<E, Object>... getters) {
81+
if (other == this) {
82+
return true;
83+
}
84+
85+
if (!getClass().isInstance(other) && !other.getClass().isInstance(this)) {
86+
return false;
87+
}
88+
89+
return stream(getters).map(getter -> Objects.equals(getters[0].apply((E) this), getters[0].apply((E) other))).allMatch(b -> b);
6590
}
6691

6792
/**
6893
* Orders by default with "nulls last".
6994
*/
7095
@Override
71-
public int compareTo(BaseEntity<I> other) {
72-
return (other == null)
73-
? -1
74-
: (getId() == null)
75-
? (other.getId() == null ? 0 : 1)
76-
: getId().compareTo(other.getId());
96+
public int compareTo(final BaseEntity<I> other) {
97+
return compareTo(other, BaseEntity::getId);
98+
}
99+
100+
@SafeVarargs
101+
@SuppressWarnings({ "unchecked", "rawtypes" })
102+
protected final <E extends BaseEntity<I>> int compareTo(final Object other, final Function<E, Object>... getters) {
103+
if (other == null) {
104+
return -1;
105+
}
106+
107+
Comparator<Object> comparator = null;
108+
109+
for (final Function getter : getters) {
110+
if (comparator == null) {
111+
comparator = comparing(getter, nullsLast(naturalOrder()));
112+
}
113+
else {
114+
comparator = comparator.thenComparing(getter, nullsLast(naturalOrder()));
115+
}
116+
}
117+
118+
return comparator.compare(this, other);
77119
}
78120

79121
/**
80122
* The default format is <code>ClassName[{id}]</code> where <code>{id}</code> defaults to <code>@hashcode</code> when null.
81123
*/
82124
@Override
83125
public String toString() {
84-
return String.format("%s[%s]", getClass().getSimpleName(), (getId() != null) ? getId() : ("@" + hashCode()));
126+
return toString(e -> requireNonNullElseGet(e.getId(), () -> ("@" + e.hashCode())));
85127
}
86128

129+
@SafeVarargs
130+
@SuppressWarnings("unchecked")
131+
protected final <E extends BaseEntity<I>> String toString(final Function<E, Object>... getters) {
132+
final var builder = new StringBuilder(getClass().getSimpleName()).append("[");
133+
134+
for (var i = 0; i < getters.length; i++) {
135+
builder.append(getters[i].apply((E) this));
136+
137+
if (i + 1 < getters.length) {
138+
builder.append(", ");
139+
}
140+
}
141+
142+
return builder.append("]").toString();
143+
}
87144
}

0 commit comments

Comments
 (0)