diff --git a/api/BUILD b/api/BUILD
index 4e98a80d..e3ab0443 100644
--- a/api/BUILD
+++ b/api/BUILD
@@ -112,7 +112,10 @@ java_library(
name = "stack_getter_common",
srcs = STACK_GETTER_COMMON_SRCS,
javacopts = ["-source 8 -target 8"],
- deps = [":checks"],
+ deps = [
+ ":checks",
+ "@google_bazel_common//third_party/java/jspecify_annotations",
+ ],
)
java_library(
diff --git a/api/src/main/java/com/google/common/flogger/DurationRateLimiter.java b/api/src/main/java/com/google/common/flogger/DurationRateLimiter.java
index 1f947fad..26088ee0 100644
--- a/api/src/main/java/com/google/common/flogger/DurationRateLimiter.java
+++ b/api/src/main/java/com/google/common/flogger/DurationRateLimiter.java
@@ -107,7 +107,7 @@ public int hashCode() {
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (obj instanceof RateLimitPeriod) {
RateLimitPeriod that = (RateLimitPeriod) obj;
return this.n == that.n && this.unit == that.unit;
diff --git a/api/src/main/java/com/google/common/flogger/LogContext.java b/api/src/main/java/com/google/common/flogger/LogContext.java
index e9a9bf2c..c48f723f 100644
--- a/api/src/main/java/com/google/common/flogger/LogContext.java
+++ b/api/src/main/java/com/google/common/flogger/LogContext.java
@@ -329,15 +329,19 @@ public String toString() {
private final long timestampNanos;
/** Additional metadata for this log statement (added via fluent API methods). */
- private MutableMetadata metadata = null;
+ private @Nullable MutableMetadata metadata = null;
+
/** The log site information for this log statement (set immediately prior to post-processing). */
- private LogSite logSite = null;
+ private @Nullable LogSite logSite = null;
+
/** Rate limit status (only set if rate limiting occurs). */
- private RateLimitStatus rateLimitStatus = null;
+ private @Nullable RateLimitStatus rateLimitStatus = null;
+
/** The template context if formatting is required (set only after post-processing). */
- private TemplateContext templateContext = null;
+ private @Nullable TemplateContext templateContext = null;
+
/** The log arguments (set only after post-processing). */
- private Object[] args = null;
+ private Object @Nullable [] args = null;
/**
* Creates a logging context with the specified level, and with a timestamp obtained from the
@@ -758,7 +762,7 @@ private void logImpl(String message, Object... args) {
// ---- Log site injection (used by pre-processors and special cases) ----
@Override
- public final API withInjectedLogSite(LogSite logSite) {
+ public final API withInjectedLogSite(@Nullable LogSite logSite) {
// First call wins (since auto-injection will typically target the log() method at the end of
// the chain and might not check for previous explicit injection). In particular it MUST be
// allowed for a caller to specify the "INVALID" log site, and have that set the field here to
diff --git a/api/src/main/java/com/google/common/flogger/LogSite.java b/api/src/main/java/com/google/common/flogger/LogSite.java
index 9ec217fd..b3e6a138 100644
--- a/api/src/main/java/com/google/common/flogger/LogSite.java
+++ b/api/src/main/java/com/google/common/flogger/LogSite.java
@@ -44,11 +44,11 @@ public abstract class LogSite implements LogSiteKey {
/**
* An singleton LogSite instance used to indicate that valid log site information cannot be
* determined. This can be used to indicate that log site information is not available by
- * injecting it via {@link LoggingApi#withInjectedLogSite} which will suppress any further
- * log site analysis for that log statement. This is also returned if stack trace analysis
- * fails for any reason.
- *
- * If a log statement does end up with invalid log site information, then any fluent logging
+ * injecting it via {@link LoggingApi#withInjectedLogSite} which will suppress any further log
+ * site analysis for that log statement. This is also returned if stack trace analysis fails for
+ * any reason.
+ *
+ *
If a log statement does end up with invalid log site information, then any fluent logging
* methods which rely on being able to look up site specific metadata will be disabled and
* essentially become "no ops".
*/
@@ -70,7 +70,7 @@ public int getLineNumber() {
}
@Override
- public String getFileName() {
+ public @Nullable String getFileName() {
return null;
}
// No need to implement equals() or hashCode() for a singleton instance.
@@ -194,7 +194,7 @@ public int getLineNumber() {
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (obj instanceof InjectedLogSite) {
InjectedLogSite other = (InjectedLogSite) obj;
// Probably not worth optimizing for "this == obj" because all strings should be interned.
diff --git a/api/src/main/java/com/google/common/flogger/MetadataKey.java b/api/src/main/java/com/google/common/flogger/MetadataKey.java
index 2f6b6bf6..7bf746c5 100644
--- a/api/src/main/java/com/google/common/flogger/MetadataKey.java
+++ b/api/src/main/java/com/google/common/flogger/MetadataKey.java
@@ -277,7 +277,7 @@ public final int hashCode() {
}
@Override
- public final boolean equals(Object obj) {
+ public final boolean equals(@Nullable Object obj) {
return super.equals(obj);
}
diff --git a/api/src/main/java/com/google/common/flogger/backend/FormatChar.java b/api/src/main/java/com/google/common/flogger/backend/FormatChar.java
index 085c0861..db7816ea 100644
--- a/api/src/main/java/com/google/common/flogger/backend/FormatChar.java
+++ b/api/src/main/java/com/google/common/flogger/backend/FormatChar.java
@@ -16,6 +16,8 @@
package com.google.common.flogger.backend;
+import org.jspecify.annotations.Nullable;
+
/**
* An enum representing the printf-like formatting characters that must be supported by all logging
* backends. It is important to note that while backends must accept any of these format specifiers,
@@ -129,10 +131,10 @@ private static boolean isLowerCase(char letter) {
}
/**
- * Returns the FormatChar instance associated with the given printf format specifier. If the
- * given character is not an ASCII letter, a runtime exception is thrown.
+ * Returns the FormatChar instance associated with the given printf format specifier. If the given
+ * character is not an ASCII letter, a runtime exception is thrown.
*/
- public static FormatChar of(char c) {
+ public static @Nullable FormatChar of(char c) {
// Get from the map by converting the char to lower-case (which is the most common case by far).
// If the given value wasn't an ASCII letter then the index will be out-of-range, but when
// called by the parser, it's always guaranteed to be an ASCII letter (but perhaps not a valid
diff --git a/api/src/main/java/com/google/common/flogger/backend/KeyValueFormatter.java b/api/src/main/java/com/google/common/flogger/backend/KeyValueFormatter.java
index 40b3f063..79abdddc 100644
--- a/api/src/main/java/com/google/common/flogger/backend/KeyValueFormatter.java
+++ b/api/src/main/java/com/google/common/flogger/backend/KeyValueFormatter.java
@@ -70,12 +70,13 @@ public final class KeyValueFormatter implements KeyValueHandler {
Double.class));
/**
- * Helper method to emit metadata key/value pairs in a format consistent with JSON. String
- * values which need to be quoted are JSON escaped, while other values are appended without
- * quoting or escaping. Labels are expected to be JSON "safe", and are never quoted. This format
- * is compatible with various "lightweight" JSON representations.
+ * Helper method to emit metadata key/value pairs in a format consistent with JSON. String values
+ * which need to be quoted are JSON escaped, while other values are appended without quoting or
+ * escaping. Labels are expected to be JSON "safe", and are never quoted. This format is
+ * compatible with various "lightweight" JSON representations.
*/
- public static void appendJsonFormattedKeyAndValue(String label, Object value, StringBuilder out) {
+ public static void appendJsonFormattedKeyAndValue(
+ String label, @Nullable Object value, StringBuilder out) {
out.append(label).append('=');
// We could also consider enums as safe if we used name() rather than toString().
if (value == null) {
diff --git a/api/src/main/java/com/google/common/flogger/backend/MessageUtils.java b/api/src/main/java/com/google/common/flogger/backend/MessageUtils.java
index a37a9116..8cf38369 100644
--- a/api/src/main/java/com/google/common/flogger/backend/MessageUtils.java
+++ b/api/src/main/java/com/google/common/flogger/backend/MessageUtils.java
@@ -29,6 +29,7 @@
import java.util.FormattableFlags;
import java.util.Formatter;
import java.util.Locale;
+import org.jspecify.annotations.Nullable;
/**
* Static utilities for classes wishing to implement their own log message formatting. None of the
@@ -82,7 +83,7 @@ public static String safeToString(Object value) {
* @param value the value to be formatted (possibly null).
* @return a non-null string representation of the given value (possibly "null").
*/
- private static String toNonNullString(Object value) {
+ private static String toNonNullString(@Nullable Object value) {
if (value == null) {
return "null";
}
diff --git a/api/src/main/java/com/google/common/flogger/backend/MetadataHandler.java b/api/src/main/java/com/google/common/flogger/backend/MetadataHandler.java
index d39bc15c..a764c297 100644
--- a/api/src/main/java/com/google/common/flogger/backend/MetadataHandler.java
+++ b/api/src/main/java/com/google/common/flogger/backend/MetadataHandler.java
@@ -24,6 +24,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import org.jspecify.annotations.Nullable;
/**
* Callback API for logger backend implementations to handle metadata keys/values. The API methods
@@ -150,7 +151,7 @@ public void handle(MetadataKey