1 | package com.reallifedeveloper.common.domain.event; | |
2 | ||
3 | import java.time.ZonedDateTime; | |
4 | import java.util.Objects; | |
5 | ||
6 | import org.checkerframework.checker.nullness.qual.Nullable; | |
7 | ||
8 | import com.reallifedeveloper.common.domain.ErrorHandling; | |
9 | import com.reallifedeveloper.common.domain.registry.CommonDomainRegistry; | |
10 | ||
11 | /** | |
12 | * An abstract base class for domain events. | |
13 | * | |
14 | * @author RealLifeDeveloper | |
15 | */ | |
16 | public abstract class AbstractDomainEvent implements DomainEvent { | |
17 | ||
18 | private static final long serialVersionUID = 1L; | |
19 | ||
20 | /** | |
21 | * The timestamp when this event occurred. | |
22 | */ | |
23 | private final ZonedDateTime eventOccurredOn; | |
24 | ||
25 | /** | |
26 | * The version of this event. In a long-lived system, it may be necessary to work with old versions of domaim events and keeping track | |
27 | * of the version makes this easier. | |
28 | */ | |
29 | private final int eventVersion; | |
30 | ||
31 | /** | |
32 | * Creates a new {@code AbstractDomainEvent} that occurred now and has a version of 1. | |
33 | * <p> | |
34 | * The time of occurrence is taken from calling the {@link com.reallifedeveloper.common.domain.TimeService#now()} method on the | |
35 | * {@link CommonDomainRegistry#timeService()}. | |
36 | */ | |
37 | public AbstractDomainEvent() { | |
38 | this(CommonDomainRegistry.timeService().now(), 1); | |
39 | } | |
40 | ||
41 | /** | |
42 | * Creates a new {@code AbstractDomainEvent} that occurred now and has the given version. | |
43 | * <p> | |
44 | * The time of occurrence is taken from calling the {@link com.reallifedeveloper.common.domain.TimeService#now()} method on the | |
45 | * {@link CommonDomainRegistry#timeService()}. | |
46 | * | |
47 | * @param eventVersion the version of the event | |
48 | */ | |
49 | public AbstractDomainEvent(int eventVersion) { | |
50 | this(CommonDomainRegistry.timeService().now(), eventVersion); | |
51 | } | |
52 | ||
53 | /** | |
54 | * Creates a new {@code AbstractDomainEvent} that occurred at the given time and has a version of 1. | |
55 | * | |
56 | * @param eventOccurredOn the date and time the event occurred | |
57 | */ | |
58 | public AbstractDomainEvent(ZonedDateTime eventOccurredOn) { | |
59 | this(eventOccurredOn, 1); | |
60 | } | |
61 | ||
62 | /** | |
63 | * Creates a new {@code AbstractDomainEvent} that occurred at the given time and has the given version. | |
64 | * | |
65 | * @param eventOccurredOn the time the event occurred | |
66 | * @param eventVersion the version of the event | |
67 | */ | |
68 | public AbstractDomainEvent(ZonedDateTime eventOccurredOn, int eventVersion) { | |
69 |
1
1. <init> : removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED |
ErrorHandling.checkNull("eventOccurredOn must not be null", eventOccurredOn); |
70 | this.eventOccurredOn = eventOccurredOn; | |
71 | this.eventVersion = eventVersion; | |
72 | } | |
73 | ||
74 | @Override | |
75 | public ZonedDateTime eventOccurredOn() { | |
76 |
1
1. eventOccurredOn : replaced return value with null for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::eventOccurredOn → KILLED |
return eventOccurredOn; |
77 | } | |
78 | ||
79 | @Override | |
80 | public int eventVersion() { | |
81 |
1
1. eventVersion : replaced int return with 0 for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::eventVersion → KILLED |
return eventVersion; |
82 | } | |
83 | ||
84 | @Override | |
85 | public String toString() { | |
86 |
1
1. toString : replaced return value with "" for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::toString → KILLED |
return getClass().getSimpleName() + "{eventOccurredOn=" + eventOccurredOn() + ", eventVersion=" + eventVersion() + "}"; |
87 | } | |
88 | ||
89 | @Override | |
90 | public int hashCode() { | |
91 |
1
1. hashCode : replaced int return with 0 for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::hashCode → KILLED |
return Objects.hash(eventOccurredOn, eventVersion); |
92 | } | |
93 | ||
94 | @Override | |
95 | public boolean equals(@Nullable Object obj) { | |
96 |
1
1. equals : negated conditional → KILLED |
if (this == obj) { |
97 |
1
1. equals : replaced boolean return with false for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::equals → KILLED |
return true; |
98 | } | |
99 |
1
1. equals : negated conditional → KILLED |
if (obj instanceof AbstractDomainEvent other) { |
100 |
3
1. equals : negated conditional → KILLED 2. equals : negated conditional → KILLED 3. equals : replaced boolean return with true for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::equals → KILLED |
return Objects.equals(eventOccurredOn, other.eventOccurredOn) && eventVersion == other.eventVersion; |
101 | } else { | |
102 |
1
1. equals : replaced boolean return with true for com/reallifedeveloper/common/domain/event/AbstractDomainEvent::equals → KILLED |
return false; |
103 | } | |
104 | } | |
105 | ||
106 | /** | |
107 | * Make finalize method final to avoid "Finalizer attacks" and corresponding SpotBugs warning (CT_CONSTRUCTOR_THROW). | |
108 | * | |
109 | * @see <a href="https://wiki.sei.cmu.edu/confluence/display/java/OBJ11-J.+Be+wary+of+letting+constructors+throw+exceptions"> | |
110 | * Explanation of finalizer attack</a> | |
111 | */ | |
112 | @Override | |
113 | @SuppressWarnings({ "checkstyle:NoFinalizer", "PMD.EmptyFinalizer", "PMD.EmptyMethodInAbstractClassShouldBeAbstract" }) | |
114 | protected final void finalize() throws Throwable { | |
115 | // Do nothing | |
116 | } | |
117 | } | |
Mutations | ||
69 |
1.1 |
|
76 |
1.1 |
|
81 |
1.1 |
|
86 |
1.1 |
|
91 |
1.1 |
|
96 |
1.1 |
|
97 |
1.1 |
|
99 |
1.1 |
|
100 |
1.1 2.2 3.3 |
|
102 |
1.1 |