12
12
*/
13
13
package org .omnifaces .persistence .model ;
14
14
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
+
15
21
import java .io .Serializable ;
22
+ import java .util .Comparator ;
16
23
import java .util .Objects ;
24
+ import java .util .function .Function ;
17
25
18
26
import jakarta .persistence .EntityListeners ;
19
27
import jakarta .persistence .MappedSuperclass ;
@@ -49,39 +57,88 @@ public abstract class BaseEntity<I extends Comparable<I> & Serializable> impleme
49
57
*/
50
58
@ Override
51
59
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 ();
55
68
}
56
69
57
70
/**
58
71
* Compares by default by entity class (proxies taken into account) and ID.
59
72
*/
60
73
@ 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 );
65
90
}
66
91
67
92
/**
68
93
* Orders by default with "nulls last".
69
94
*/
70
95
@ 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 );
77
119
}
78
120
79
121
/**
80
122
* The default format is <code>ClassName[{id}]</code> where <code>{id}</code> defaults to <code>@hashcode</code> when null.
81
123
*/
82
124
@ Override
83
125
public String toString () {
84
- return String . format ( "%s[%s]" , getClass (). getSimpleName (), (getId () != null ) ? getId () : ( "@" + hashCode ()));
126
+ return toString ( e -> requireNonNullElseGet ( e . getId (), () -> ( "@" + e . hashCode () )));
85
127
}
86
128
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
+ }
87
144
}
0 commit comments