Skip to content

Commit 6841f17

Browse files
schlosnabulldozer-bot[bot]
authored andcommitted
[improvement] Enable NullAway gradle checks (#99)
<!-- PR title should start with '[fix]', '[improvement]' or '[break]' if this PR would cause a patch, minor or major SemVer bump. Omit the prefix if this PR doesn't warrant a standalone release. --> ## Before this PR <!-- Describe the problem you encountered with the current state of the world (or link to an issue) and why it's important to fix now. --> The safe-logging library did not explicitly annotate `Arg` and its subtypes, so consumers of this library would receive false-positive warnings when using static analysis checks such as [NullAway](https://github.com/uber/NullAway) or IntelliJ nullability checks, for example the below as seen in palantir/tritium#152 where [use of `UnsafeArg.of` with a `@Nullable` value](https://github.com/palantir/tritium/blob/develop/tritium-core/src/main/java/com/palantir/tritium/event/CompositeInvocationEventHandler.java#L142) is mistakenly flagged: ``` warning: [NullAway] passing @nullable parameter 'context' where @nonnull is required UnsafeArg.of("context", context), ^ ``` ## After this PR <!-- Describe at a high-level why this approach is better. --> Enables [NullAway](https://github.com/uber/NullAway) gradle build checks and appropriately annotates Arg and its subtypes to support proper nullability analysis. <!-- Reference any existing GitHub issues, e.g. 'fixes #000' or 'relevant to #000' --> Relevant to palantir/tritium#152 and supersedes #97 The NullAway checks identified one possible issue in safe-logging's `LoggableExceptionAssert`, and this has been corrected. * Handle null LoggableExceptionAssert arg, addresses NullAway warnings: ``` > Task :preconditions-assertj:compileJava /Volumes/git/safe-logging/preconditions-assertj/src/main/java/com/palantir/logsafe/testing/LoggableExceptionAssert.java:30: warning: [NullAway] initializer method does not guarantee @nonnull field argsAssert is initialized along all control-flow paths (remember to check for exceptions or early returns). public LoggableExceptionAssert(T actual) { ^ (see http://t.uber.com/nullaway ) /Volumes/git/safe-logging/preconditions-assertj/src/main/java/com/palantir/logsafe/testing/LoggableExceptionAssert.java:33: warning: [NullAway] assigning @nullable expression to @nonnull field argsAssert = actual == null ? null : new ArgsAssert(actual.getArgs()); ^ (see http://t.uber.com/nullaway ) 2 warnings ``` Another error-prone warning identified a potential issue with `Arg.equals` implementation * Arg.equals checks isSafeForLogging, addresses EqualsGetClass error-prone finding: ``` > Task :safe-logging:compileJava /Volumes/git/safe-logging/safe-logging/src/main/java/com/palantir/logsafe/Arg.java:51: warning: [EqualsGetClass] Overriding Object#equals in a non-final class by using getClass rather than instanceof breaks substitutability of subclasses. public final boolean equals(Object other) { ^ (see https://errorprone.info/bugpattern/EqualsGetClass) Did you mean 'if (!(other instanceof Arg)) {'? 1 warning ```
1 parent fbbaffa commit 6841f17

File tree

7 files changed

+41
-8
lines changed

7 files changed

+41
-8
lines changed

build.gradle

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,15 @@ subprojects {
5050
}
5151
}
5252
tasks.check.dependsOn(javadoc)
53+
54+
plugins.withId('com.palantir.baseline-error-prone', {
55+
dependencies {
56+
compileOnly 'com.google.code.findbugs:jsr305'
57+
annotationProcessor 'com.uber.nullaway:nullaway'
58+
}
59+
tasks.withType(JavaCompile) {
60+
options.errorprone.errorproneArgs += ['-XepOpt:NullAway:AnnotatedPackages=com.palantir']
61+
}
62+
})
5363
}
5464

preconditions-assertj/src/main/java/com/palantir/logsafe/testing/LoggableExceptionAssert.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.palantir.logsafe.Arg;
2020
import com.palantir.logsafe.SafeLoggable;
21+
import java.util.Collections;
2122
import java.util.List;
2223
import org.assertj.core.api.AbstractThrowableAssert;
2324
import org.assertj.core.api.ListAssert;
@@ -30,7 +31,8 @@ public class LoggableExceptionAssert<T extends Throwable & SafeLoggable>
3031
public LoggableExceptionAssert(T actual) {
3132
super(actual, LoggableExceptionAssert.class);
3233

33-
argsAssert = actual == null ? null : new ArgsAssert(actual.getArgs());
34+
List<Arg<?>> args = actual == null ? Collections.emptyList() : actual.getArgs();
35+
argsAssert = new ArgsAssert(args);
3436
}
3537

3638
/**

preconditions-assertj/src/test/java/com/palantir/logsafe/testing/LoggableExceptionAssertionsTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ public void failIncorrectAssertThatLoggableExceptionThrownBy() {
156156
}));
157157
}
158158

159+
@Test
160+
public void nullArgsAssert() {
161+
assertThatThrownBy(() -> new LoggableExceptionAssert<>(null).isNotNull())
162+
.isInstanceOf(AssertionError.class)
163+
.hasMessageContaining("Expecting actual not to be null");
164+
}
165+
159166
private static class LoggableException extends Throwable implements SafeLoggable {
160167
LoggableException() {
161168
super("test message");

safe-logging/src/main/java/com/palantir/logsafe/Arg.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,31 @@
1818

1919
import java.io.Serializable;
2020
import java.util.Objects;
21+
import javax.annotation.Nonnull;
22+
import javax.annotation.Nullable;
2123

2224
/** A wrapper around an argument used to build a formatted message. */
2325
public abstract class Arg<T> implements Serializable {
2426

27+
@Nonnull
2528
private final String name;
29+
30+
@Nullable
2631
private final T value;
2732

28-
protected Arg(String name, T value) {
33+
protected Arg(String name, @Nullable T value) {
2934
this.name = Objects.requireNonNull(name, "name may not be null");
3035
this.value = value;
3136
}
3237

3338
/** A name describing this argument. */
39+
@Nonnull
3440
public final String getName() {
3541
return name;
3642
}
3743

3844
/** The value of this argument (which may be {@code null}). */
45+
@Nullable
3946
public final T getValue() {
4047
return value;
4148
}
@@ -52,12 +59,13 @@ public final boolean equals(Object other) {
5259
if (this == other) {
5360
return true;
5461
}
55-
if (other == null || getClass() != other.getClass()) {
62+
if (!(other instanceof Arg)) {
5663
return false;
5764
}
5865
Arg<?> arg = (Arg<?>) other;
5966
return Objects.equals(name, arg.name)
60-
&& Objects.equals(value, arg.value);
67+
&& Objects.equals(value, arg.value)
68+
&& (isSafeForLogging() == arg.isSafeForLogging());
6169
}
6270

6371
@Override

safe-logging/src/main/java/com/palantir/logsafe/SafeArg.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616

1717
package com.palantir.logsafe;
1818

19+
import javax.annotation.Nullable;
20+
1921
/** A wrapper around an argument known to be safe for logging. */
2022
public final class SafeArg<T> extends Arg<T> {
2123

22-
private SafeArg(String name, T value) {
24+
private SafeArg(String name, @Nullable T value) {
2325
super(name, value);
2426
}
2527

26-
public static <T> SafeArg<T> of(String name, T value) {
28+
public static <T> SafeArg<T> of(String name, @Nullable T value) {
2729
return new SafeArg<>(name, value);
2830
}
2931

safe-logging/src/main/java/com/palantir/logsafe/UnsafeArg.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616

1717
package com.palantir.logsafe;
1818

19+
import javax.annotation.Nullable;
20+
1921
/** A wrapper around an argument that is not safe for logging. */
2022
public final class UnsafeArg<T> extends Arg<T> {
2123

22-
private UnsafeArg(String name, T value) {
24+
private UnsafeArg(String name, @Nullable T value) {
2325
super(name, value);
2426
}
2527

26-
public static <T> UnsafeArg<T> of(String name, T value) {
28+
public static <T> UnsafeArg<T> of(String name, @Nullable T value) {
2729
return new UnsafeArg<>(name, value);
2830
}
2931

versions.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
com.google.code.findbugs:jsr305 = 3.0.2
2+
com.google.guava:guava = 23.5-jre
3+
com.uber.nullaway:nullaway = 0.6.4
24
junit:junit = 4.12
35
org.assertj:assertj-core = 3.11.1
46

0 commit comments

Comments
 (0)