1212 */
1313package 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+
1521import java .io .Serializable ;
22+ import java .util .Comparator ;
1623import java .util .Objects ;
24+ import java .util .function .Function ;
1725
1826import jakarta .persistence .EntityListeners ;
1927import 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