diff --git a/README.md b/README.md
index 6867e5e..c55ef0a 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ To deserialize a CodeTF file using these objects, simply deserialize with Jackso
## Gradle
```kotlin
-implementation("io.codemodder:codetf-java:4.2.0")
+implementation("io.codemodder:codetf-java:4.2.1")
```
## Maven
@@ -25,7 +25,7 @@ implementation("io.codemodder:codetf-java:4.2.0")
When a codemod is able to fix a finding, it should create a {@link FixedFinding} instance. If + * a codemod would typically fix findings of this type but cannot, it can create an {@link + * UnfixedFinding} instance to explain why. + * + *
Findings typically have some ID specified in the detector results.
+ */
+public abstract sealed class Finding permits FixedFinding, UnfixedFinding {
+
+ private final String id;
+ private final DetectorRule rule;
+
+ Finding(final String id, final DetectorRule rule) {
+ this.id = id;
+ this.rule = Objects.requireNonNull(rule);
+ }
+
+ Finding(final DetectorRule rule) {
+ this(null, rule);
+ }
+
+ /**
+ * @return the ID of the finding, or {@code null} if the finding has no ID
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * @return the rule that detected the finding
+ */
+ public DetectorRule getRule() {
+ return rule;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final Finding finding = (Finding) o;
+ return Objects.equals(id, finding.id) && rule.equals(finding.rule);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hashCode(id);
+ result = 31 * result + rule.hashCode();
+ return result;
+ }
+}
diff --git a/src/main/java/io/codemodder/codetf/FixedFinding.java b/src/main/java/io/codemodder/codetf/FixedFinding.java
index 87a502c..41ae113 100644
--- a/src/main/java/io/codemodder/codetf/FixedFinding.java
+++ b/src/main/java/io/codemodder/codetf/FixedFinding.java
@@ -2,40 +2,28 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.Objects;
/** Describes a fixed finding. */
-public final class FixedFinding {
-
- private final String id;
- private final DetectorRule rule;
+public final class FixedFinding extends Finding {
@JsonCreator
public FixedFinding(
@JsonProperty(value = "id", index = 1) final String id,
@JsonProperty(value = "rule", index = 2) final DetectorRule rule) {
- this.id = CodeTFValidator.requireNonBlank(id);
- this.rule = Objects.requireNonNull(rule);
- }
-
- public String getId() {
- return id;
+ super(id, rule);
}
- public DetectorRule getRule() {
- return rule;
+ public FixedFinding(final DetectorRule rule) {
+ super(rule);
}
@Override
public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- FixedFinding that = (FixedFinding) o;
- return Objects.equals(id, that.id) && Objects.equals(rule, that.rule);
+ return super.equals(o);
}
@Override
public int hashCode() {
- return Objects.hash(id, rule);
+ return super.hashCode();
}
}
diff --git a/src/main/java/io/codemodder/codetf/UnfixedFinding.java b/src/main/java/io/codemodder/codetf/UnfixedFinding.java
index 9e468d2..67d10c8 100644
--- a/src/main/java/io/codemodder/codetf/UnfixedFinding.java
+++ b/src/main/java/io/codemodder/codetf/UnfixedFinding.java
@@ -5,10 +5,8 @@
import java.util.Objects;
/** Describes an unfixed finding. */
-public final class UnfixedFinding {
+public final class UnfixedFinding extends Finding {
- private final String id;
- private final DetectorRule rule;
private final String path;
private final Integer line;
private final String reason;
@@ -20,15 +18,18 @@ public UnfixedFinding(
@JsonProperty(value = "path", index = 3) final String path,
@JsonProperty(value = "line", index = 4) final Integer line,
@JsonProperty(value = "reason", index = 5) final String reason) {
- this.id = CodeTFValidator.requireNonBlank(id);
- this.rule = Objects.requireNonNull(rule);
+ super(id, rule);
this.path = CodeTFValidator.requireNonBlank(path);
this.line = line;
this.reason = CodeTFValidator.requireNonBlank(reason);
}
- public String getId() {
- return id;
+ public UnfixedFinding(
+ @JsonProperty(value = "rule", index = 2) final DetectorRule rule,
+ @JsonProperty(value = "path", index = 3) final String path,
+ @JsonProperty(value = "line", index = 4) final Integer line,
+ @JsonProperty(value = "reason", index = 5) final String reason) {
+ this(null, rule, path, line, reason);
}
public String getPath() {
@@ -39,10 +40,6 @@ public String getReason() {
return reason;
}
- public DetectorRule getRule() {
- return rule;
- }
-
public Integer getLine() {
return line;
}
@@ -50,17 +47,18 @@ public Integer getLine() {
@Override
public boolean equals(final Object o) {
if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- UnfixedFinding that = (UnfixedFinding) o;
- return Objects.equals(id, that.id)
- && Objects.equals(rule, that.rule)
- && Objects.equals(path, that.path)
- && Objects.equals(line, that.line)
- && Objects.equals(reason, that.reason);
+ if (!(o instanceof final UnfixedFinding that)) return false;
+ if (!super.equals(o)) return false;
+
+ return path.equals(that.path) && Objects.equals(line, that.line) && reason.equals(that.reason);
}
@Override
public int hashCode() {
- return Objects.hash(id, rule, path, line, reason);
+ int result = super.hashCode();
+ result = 31 * result + path.hashCode();
+ result = 31 * result + Objects.hashCode(line);
+ result = 31 * result + reason.hashCode();
+ return result;
}
}
diff --git a/src/test/java/io/codemodder/codetf/CodeTFResultTest.java b/src/test/java/io/codemodder/codetf/CodeTFResultTest.java
index 3a87a8f..b39e1de 100644
--- a/src/test/java/io/codemodder/codetf/CodeTFResultTest.java
+++ b/src/test/java/io/codemodder/codetf/CodeTFResultTest.java
@@ -112,8 +112,6 @@ void it_creates_finding() {
FixedFinding finding = new FixedFinding("finding", rule);
assertEquals("finding", finding.getId());
assertThrows(NullPointerException.class, () -> new FixedFinding("finding", null));
- assertThrows(IllegalArgumentException.class, () -> new FixedFinding("", rule));
- assertThrows(IllegalArgumentException.class, () -> new FixedFinding(null, rule));
}
@Test
diff --git a/src/test/java/io/codemodder/codetf/EqualsAndHashcodeTests.java b/src/test/java/io/codemodder/codetf/EqualsAndHashcodeTests.java
new file mode 100644
index 0000000..f877bf9
--- /dev/null
+++ b/src/test/java/io/codemodder/codetf/EqualsAndHashcodeTests.java
@@ -0,0 +1,50 @@
+package io.codemodder.codetf;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import org.junit.jupiter.api.Test;
+
+public interface EqualsAndHashcodeTests