0
# Warning System
1
2
Comprehensive warning system for suppressing specific validation rules when they don't apply to particular use cases. EqualsVerifier provides 17 different warning types that can be suppressed individually or in combination to handle edge cases and specific design patterns.
3
4
## Capabilities
5
6
### Warning Enum
7
8
The complete set of warnings that can be suppressed in EqualsVerifier.
9
10
```java { .api }
11
/**
12
* Enum of warnings that can be suppressed in EqualsVerifier.
13
* @see nl.jqno.equalsverifier.api.EqualsVerifierApi#suppress(Warning...)
14
*/
15
public enum Warning {
16
ALL_FIELDS_SHOULD_BE_USED,
17
ALL_NONFINAL_FIELDS_SHOULD_BE_USED,
18
REFERENCE_EQUALITY,
19
IDENTICAL_COPY,
20
IDENTICAL_COPY_FOR_VERSIONED_ENTITY,
21
INHERITED_DIRECTLY_FROM_OBJECT,
22
NO_EXAMPLE_FOR_CACHED_HASHCODE,
23
NONFINAL_FIELDS,
24
NULL_FIELDS,
25
STRICT_HASHCODE,
26
STRICT_INHERITANCE,
27
SURROGATE_KEY,
28
SURROGATE_OR_BUSINESS_KEY,
29
JPA_GETTER,
30
TRANSIENT_FIELDS,
31
BIGDECIMAL_EQUALITY,
32
@Deprecated ZERO_FIELDS
33
}
34
```
35
36
### Field Usage Warnings
37
38
Warnings related to how fields are used in equals and hashCode methods.
39
40
#### ALL_FIELDS_SHOULD_BE_USED
41
42
```java { .api }
43
/**
44
* Signals that not all fields are relevant in the equals contract. EqualsVerifier
45
* will not fail if one or more fields do not affect the outcome of equals.
46
*
47
* Only applies to non-transient fields.
48
*/
49
ALL_FIELDS_SHOULD_BE_USED
50
```
51
52
**Usage Examples:**
53
54
```java
55
// Class where only some fields are used in equals
56
public class Person {
57
private String firstName;
58
private String lastName;
59
private Date birthDate;
60
private String socialSecurityNumber; // Not used in equals
61
62
@Override
63
public boolean equals(Object obj) {
64
// Only compares firstName, lastName, birthDate
65
// socialSecurityNumber is ignored
66
}
67
}
68
69
EqualsVerifier.forClass(Person.class)
70
.suppress(Warning.ALL_FIELDS_SHOULD_BE_USED)
71
.verify();
72
```
73
74
#### ALL_NONFINAL_FIELDS_SHOULD_BE_USED
75
76
```java { .api }
77
/**
78
* Signals that non-final fields are not relevant in the equals contract. EqualsVerifier
79
* will not fail if one or more non-final fields do not affect the outcome of equals.
80
*
81
* Only applies to non-transient fields.
82
*/
83
ALL_NONFINAL_FIELDS_SHOULD_BE_USED
84
```
85
86
**Usage Examples:**
87
88
```java
89
// Class where non-final fields are not part of equals
90
public class ImmutablePerson {
91
private final String name;
92
private final int age;
93
private String nickname; // Non-final, not used in equals
94
95
@Override
96
public boolean equals(Object obj) {
97
// Only compares final fields: name and age
98
}
99
}
100
101
EqualsVerifier.forClass(ImmutablePerson.class)
102
.suppress(Warning.ALL_NONFINAL_FIELDS_SHOULD_BE_USED)
103
.verify();
104
```
105
106
#### NONFINAL_FIELDS
107
108
```java { .api }
109
/**
110
* Disables checks for non-final fields on which equals and hashCode depend.
111
*
112
* EqualsVerifier's standard behaviour is to disallow non-final fields being used in
113
* equals and hashCode methods, since classes that depend on non-final fields in
114
* these methods cannot reliably be used in collections.
115
*
116
* However, sometimes an external library requires that fields be non-final. An example of
117
* this are Java Beans. In such a case, suppress this warning to prevent EqualsVerifier
118
* from checking for non-final fields.
119
*/
120
NONFINAL_FIELDS
121
```
122
123
**Usage Examples:**
124
125
```java
126
// JavaBean with non-final fields used in equals
127
public class PersonBean {
128
private String name; // Non-final but used in equals
129
private int age; // Non-final but used in equals
130
131
// Getters and setters...
132
133
@Override
134
public boolean equals(Object obj) {
135
// Uses non-final fields
136
}
137
}
138
139
EqualsVerifier.forClass(PersonBean.class)
140
.suppress(Warning.NONFINAL_FIELDS)
141
.verify();
142
```
143
144
### Equality Contract Warnings
145
146
Warnings related to the fundamental equality contract.
147
148
#### REFERENCE_EQUALITY
149
150
```java { .api }
151
/**
152
* Disables the check for reference equality on fields.
153
*
154
* EqualsVerifier will check if the equals method calls equals on the object fields
155
* of the class under test, instead of the == operator, since normally this signifies a
156
* mistake (e.g. comparing string fields with ==).
157
*
158
* However, sometimes == is used intentionally, or the field in question doesn't
159
* implement equals itself, so a call to the equals method of that field is
160
* essentially a reference equality check instead of a value equality check. In these cases,
161
* this warning can be suppressed.
162
*/
163
REFERENCE_EQUALITY
164
```
165
166
**Usage Examples:**
167
168
```java
169
// Class that intentionally uses == for object comparison
170
public class Node {
171
private Node parent;
172
private String data;
173
174
@Override
175
public boolean equals(Object obj) {
176
if (!(obj instanceof Node)) return false;
177
Node other = (Node) obj;
178
return this.parent == other.parent && // Intentional reference equality
179
Objects.equals(this.data, other.data);
180
}
181
}
182
183
EqualsVerifier.forClass(Node.class)
184
.suppress(Warning.REFERENCE_EQUALITY)
185
.verify();
186
```
187
188
#### IDENTICAL_COPY
189
190
```java { .api }
191
/**
192
* Disables the check, when the equals method is overridden in the class under test,
193
* that an instance of this class should be equal to an identical copy of itself.
194
*
195
* Normally, it is important that an object be equal to an identical copy of itself: after
196
* all, this is the point of overriding equals in the first place.
197
*
198
* However, when the class is part of a hierarchy, but should be (pseudo-)singleton, it can
199
* be useful to suppress this warning. This can happen in certain implementations of the Null
200
* Object Pattern, for example.
201
*
202
* If this warning is suppressed, and it turns out that an instance of the class under test
203
* is equal to an identical copy of itself after all, EqualsVerifier will fail.
204
*/
205
IDENTICAL_COPY
206
```
207
208
**Usage Examples:**
209
210
```java
211
// Singleton or Null Object Pattern implementation
212
public class NullPerson extends Person {
213
private static final NullPerson INSTANCE = new NullPerson();
214
215
public static NullPerson getInstance() {
216
return INSTANCE;
217
}
218
219
@Override
220
public boolean equals(Object obj) {
221
// Only equal to the same singleton instance
222
return this == obj;
223
}
224
}
225
226
EqualsVerifier.forClass(NullPerson.class)
227
.suppress(Warning.IDENTICAL_COPY)
228
.verify();
229
```
230
231
#### IDENTICAL_COPY_FOR_VERSIONED_ENTITY
232
233
```java { .api }
234
/**
235
* Disables the check, when the equals method is overridden in the class under test,
236
* that an instance of this class should be equal to an identical copy of itself.
237
*
238
* Normally, it is important that an object be equal to an identical copy of itself: after
239
* all, this is the point of overriding equals in the first place.
240
*
241
* However, when the class is a kind of versioned entity and there is an id field
242
* that is zero when the object is new, it is often the case that two new objects are never
243
* equal to each other. In these cases, it can be useful to suppress this warning.
244
*
245
* You cannot use IDENTICAL_COPY in these cases, because when the ids are
246
* equal, the objects should be, too, and EqualsVerifier would fail in this case.
247
*
248
* If this warning is suppressed, and it turns out that an instance of the class under test
249
* is equal to an identical copy of itself after all, EqualsVerifier will NOT fail.
250
*/
251
IDENTICAL_COPY_FOR_VERSIONED_ENTITY
252
```
253
254
**Usage Examples:**
255
256
```java
257
// Entity with auto-generated ID that affects equals
258
public class VersionedEntity {
259
private Long id; // 0 or null for new entities
260
private String name;
261
262
@Override
263
public boolean equals(Object obj) {
264
if (!(obj instanceof VersionedEntity)) return false;
265
VersionedEntity other = (VersionedEntity) obj;
266
267
// New entities (id == null) are never equal
268
if (this.id == null || other.id == null) return false;
269
270
return Objects.equals(this.id, other.id);
271
}
272
}
273
274
EqualsVerifier.forClass(VersionedEntity.class)
275
.suppress(Warning.IDENTICAL_COPY_FOR_VERSIONED_ENTITY)
276
.verify();
277
```
278
279
### Inheritance Warnings
280
281
Warnings related to inheritance hierarchies and method overriding.
282
283
#### STRICT_INHERITANCE
284
285
```java { .api }
286
/**
287
* Disables some of the stricter inheritance tests.
288
*
289
* EqualsVerifier's standard behaviour, if T is not final and neither are its equals
290
* and hashCode methods, is to require a reference to a subclass of T for which
291
* no instance can be equal to any instance of T, to make sure that subclasses that can redefine
292
* equals or hashCode don't break the contract; or it asks to call the usingGetClass
293
* method if T uses getClass() instead of instanceof in its equals method.
294
*
295
* Some may find that too strict for their liking; suppressing this warning disables that
296
* test.
297
*
298
* @see nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi#withRedefinedSubclass(Class)
299
*/
300
STRICT_INHERITANCE
301
```
302
303
**Usage Examples:**
304
305
```java
306
// Non-final class without strict inheritance checks
307
public class Person { // Not final
308
private String name;
309
310
@Override
311
public boolean equals(Object obj) {
312
if (!(obj instanceof Person)) return false;
313
Person other = (Person) obj;
314
return Objects.equals(this.name, other.name);
315
}
316
}
317
318
EqualsVerifier.forClass(Person.class)
319
.suppress(Warning.STRICT_INHERITANCE)
320
.verify();
321
```
322
323
#### INHERITED_DIRECTLY_FROM_OBJECT
324
325
```java { .api }
326
/**
327
* Disables the check that verifies equals is actually overridden.
328
*
329
* Can be used when a whole package of classes is automatically scanned and presented to
330
* EqualsVerifier, and one or more of them don't need to override equals.
331
*/
332
INHERITED_DIRECTLY_FROM_OBJECT
333
```
334
335
**Usage Examples:**
336
337
```java
338
// Class that doesn't override equals but is included in package scan
339
public class SimpleDataClass {
340
private final String value;
341
342
public SimpleDataClass(String value) {
343
this.value = value;
344
}
345
346
// No equals override - inherits from Object
347
}
348
349
// When scanning packages that include classes without equals
350
EqualsVerifier.forPackage("com.example.model")
351
.suppress(Warning.INHERITED_DIRECTLY_FROM_OBJECT)
352
.verify();
353
```
354
355
### Null Handling Warnings
356
357
#### NULL_FIELDS
358
359
```java { .api }
360
/**
361
* Disables checks for NullPointerException within equals, hashCode and toString methods.
362
*
363
* Sometimes the constructor of a class makes sure no field can be null. If this is the case,
364
* and if the fields cannot be made null later in the lifecycle of the class by setters or other
365
* methods, suppress this warning to disable the check for NullPointerException.
366
*/
367
NULL_FIELDS
368
```
369
370
**Usage Examples:**
371
372
```java
373
// Class with constructor that prevents null fields
374
public class Person {
375
private final String name;
376
private final int age;
377
378
public Person(String name, int age) {
379
this.name = Objects.requireNonNull(name);
380
this.age = age;
381
}
382
383
@Override
384
public boolean equals(Object obj) {
385
// Safe to call methods on name without null check
386
// because constructor ensures it's never null
387
}
388
}
389
390
EqualsVerifier.forClass(Person.class)
391
.suppress(Warning.NULL_FIELDS)
392
.verify();
393
```
394
395
### HashCode Warnings
396
397
#### STRICT_HASHCODE
398
399
```java { .api }
400
/**
401
* Disables the check that all fields used in equals must also be used in hashCode.
402
*
403
* This is useful when bringing legacy systems under test, where you don't want to change the
404
* existing hashCode behaviour but you do want to use EqualsVerifier.
405
*
406
* Note that hashCodes with higher distributions give better performance when used in
407
* collections such as HashMap. Therefore, if possible, you should use all
408
* fields that are used in equals, in hashCode as well.
409
*/
410
STRICT_HASHCODE
411
```
412
413
**Usage Examples:**
414
415
```java
416
// Legacy class with inconsistent equals/hashCode
417
public class LegacyPerson {
418
private String firstName;
419
private String lastName;
420
private int socialSecurityNumber;
421
422
@Override
423
public boolean equals(Object obj) {
424
// Uses all three fields
425
}
426
427
@Override
428
public int hashCode() {
429
// Legacy implementation only uses firstName and lastName
430
return Objects.hash(firstName, lastName);
431
}
432
}
433
434
EqualsVerifier.forClass(LegacyPerson.class)
435
.suppress(Warning.STRICT_HASHCODE)
436
.verify();
437
```
438
439
#### NO_EXAMPLE_FOR_CACHED_HASHCODE
440
441
```java { .api }
442
/**
443
* Disables the example check for cached hashCode.
444
*
445
* The example check verifies that the cached hashCode is properly initialized. You
446
* can use this, if creating an example object is too cumbersome. In this case, null can be
447
* passed as an example.
448
*
449
* Note that suppressing this warning can be dangerous and should only be done in unusual
450
* circumstances.
451
*/
452
NO_EXAMPLE_FOR_CACHED_HASHCODE
453
```
454
455
**Usage Examples:**
456
457
```java
458
// When providing example for cached hashCode is difficult
459
EqualsVerifier.forClass(ComplexCachedClass.class)
460
.withCachedHashCode("cachedHashCode", "calculateHashCode", null)
461
.suppress(Warning.NO_EXAMPLE_FOR_CACHED_HASHCODE)
462
.verify();
463
```
464
465
### JPA and Database Warnings
466
467
#### SURROGATE_KEY
468
469
```java { .api }
470
/**
471
* Disables the check that fields marked with the @Id or @EmbeddedId annotations in JPA entities
472
* may not be used in the equals contract.
473
*
474
* When this warning is suppressed, the fields marked with @Id or @EmbeddedId will become the
475
* entity's surrogate key. Only these fields can now be part of the equals contract; all
476
* other fields may no longer be used in equals.
477
*/
478
SURROGATE_KEY
479
```
480
481
**Usage Examples:**
482
483
```java
484
// JPA Entity using ID as surrogate key
485
@Entity
486
public class UserEntity {
487
@Id
488
@GeneratedValue
489
private Long id;
490
491
private String username;
492
private String email;
493
494
@Override
495
public boolean equals(Object obj) {
496
if (!(obj instanceof UserEntity)) return false;
497
UserEntity other = (UserEntity) obj;
498
return Objects.equals(this.id, other.id); // Only uses ID
499
}
500
}
501
502
EqualsVerifier.forClass(UserEntity.class)
503
.suppress(Warning.SURROGATE_KEY)
504
.verify();
505
```
506
507
#### SURROGATE_OR_BUSINESS_KEY
508
509
```java { .api }
510
/**
511
* Disables the check that fields marked with the @Id or @EmbeddedId annotations in JPA entities
512
* may not be used in the equals contract.
513
*
514
* When this warning is suppressed, all fields will become part of the entity's key, and
515
* EqualsVerifier will operate as if the entity were a normal class.
516
*/
517
SURROGATE_OR_BUSINESS_KEY
518
```
519
520
**Usage Examples:**
521
522
```java
523
// JPA Entity using business key (all fields)
524
@Entity
525
public class ProductEntity {
526
@Id
527
@GeneratedValue
528
private Long id;
529
530
private String name;
531
private String sku;
532
533
@Override
534
public boolean equals(Object obj) {
535
// Uses all fields including ID
536
}
537
}
538
539
EqualsVerifier.forClass(ProductEntity.class)
540
.suppress(Warning.SURROGATE_OR_BUSINESS_KEY)
541
.verify();
542
```
543
544
#### JPA_GETTER
545
546
```java { .api }
547
/**
548
* Disables the check that collection fields in JPA, or @Basic fields marked with
549
* FetchType.LAZY, should be accessed through their getter methods in equals and
550
* hashCode methods.
551
*
552
* Normally, it is necessary to go through the getter for these fields, because their
553
* content may not be materialized in some instances. Calling the getter will materialize them,
554
* but referencing the field directly will not. This can lead to situations where the
555
* equals method of objects that should be equal to each other returns false, because
556
* one instance has the content materialized and the other does not.
557
*/
558
JPA_GETTER
559
```
560
561
**Usage Examples:**
562
563
```java
564
// JPA Entity that accesses fields directly instead of using getters
565
@Entity
566
public class OrderEntity {
567
@Id
568
private Long id;
569
570
@OneToMany(fetch = FetchType.LAZY)
571
private List<OrderItem> items;
572
573
@Override
574
public boolean equals(Object obj) {
575
// Accesses items field directly instead of getItems()
576
}
577
}
578
579
EqualsVerifier.forClass(OrderEntity.class)
580
.suppress(Warning.JPA_GETTER)
581
.verify();
582
```
583
584
### Field Type Warnings
585
586
#### TRANSIENT_FIELDS
587
588
```java { .api }
589
/**
590
* Disables the check that transient fields not be part of the equals contract.
591
*
592
* EqualsVerifier's standard behaviour is to disallow transient fields being used in
593
* equals and hashCode methods, since these fields may not be restored to their
594
* original state after deserialization, which would break equals.
595
*
596
* If measures are taken that this will never happen, this warning can be suppressed to
597
* disable EqualsVerifier's transience test.
598
*/
599
TRANSIENT_FIELDS
600
```
601
602
**Usage Examples:**
603
604
```java
605
// Class that uses transient fields in equals (with proper serialization handling)
606
public class CustomSerializableClass implements Serializable {
607
private String name;
608
private transient String cachedValue; // Used in equals but handled in serialization
609
610
@Override
611
public boolean equals(Object obj) {
612
// Uses transient field with proper handling
613
}
614
615
private void readObject(ObjectInputStream in) {
616
// Properly restore transient field during deserialization
617
}
618
}
619
620
EqualsVerifier.forClass(CustomSerializableClass.class)
621
.suppress(Warning.TRANSIENT_FIELDS)
622
.verify();
623
```
624
625
#### BIGDECIMAL_EQUALITY
626
627
```java { .api }
628
/**
629
* Disables the check that equality of BigDecimal fields is implemented using
630
* compareTo rather than equals.
631
*
632
* BigDecimal objects that are equal using compareTo are not necessarily
633
* equal using equals, for example the values of 1 and 1.0.
634
* For variants of the same value to be considered equal, classes with BigDecimal
635
* fields should use compareTo to check equality of non-null BigDecimal
636
* references and produce the same hashcode for all equal variants.
637
*
638
* EqualsVerifier checks for this by default but it can be disabled by suppressing
639
* this warning.
640
*/
641
BIGDECIMAL_EQUALITY
642
```
643
644
**Usage Examples:**
645
646
```java
647
// Class that uses BigDecimal.equals() instead of compareTo()
648
public class Price {
649
private BigDecimal amount;
650
651
@Override
652
public boolean equals(Object obj) {
653
if (!(obj instanceof Price)) return false;
654
Price other = (Price) obj;
655
return Objects.equals(this.amount, other.amount); // Uses equals, not compareTo
656
}
657
}
658
659
EqualsVerifier.forClass(Price.class)
660
.suppress(Warning.BIGDECIMAL_EQUALITY)
661
.verify();
662
```
663
664
### Deprecated Warnings
665
666
#### ZERO_FIELDS (Deprecated)
667
668
```java { .api }
669
/**
670
* No longer does anything.
671
* @deprecated Use SingleTypeEqualsVerifierApi.withPrefabValuesForField(String, Object, Object) instead.
672
*/
673
@Deprecated
674
ZERO_FIELDS
675
```
676
677
### Common Warning Combinations
678
679
**Standard IDE-generated code:**
680
681
```java
682
EqualsVerifier.forClass(MyClass.class)
683
.suppress(Warning.STRICT_INHERITANCE, Warning.NONFINAL_FIELDS)
684
.verify();
685
```
686
687
**JPA entities:**
688
689
```java
690
EqualsVerifier.forClass(MyEntity.class)
691
.suppress(Warning.SURROGATE_KEY, Warning.JPA_GETTER)
692
.verify();
693
```
694
695
**Legacy code migration:**
696
697
```java
698
EqualsVerifier.forClass(LegacyClass.class)
699
.suppress(Warning.STRICT_HASHCODE, Warning.NONFINAL_FIELDS, Warning.NULL_FIELDS)
700
.verify();
701
```
702
703
**Package scanning:**
704
705
```java
706
EqualsVerifier.forPackage("com.example.model")
707
.suppress(Warning.INHERITED_DIRECTLY_FROM_OBJECT, Warning.STRICT_INHERITANCE)
708
.verify();
709
```