or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-api.mdindex.mdmultiple-class-api.mdrelaxed-equality-api.mdsingle-class-api.mdwarning-system.md

warning-system.mddocs/

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

```