From b8cb31ab767453a6229d488a97b590c158760968 Mon Sep 17 00:00:00 2001 From: Michael Morrison <517502+mmorrisontx@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:36:00 -0600 Subject: [PATCH] Swap from jsr305 to checker --- gradle/libs.versions.toml | 2 +- io/build.gradle | 3 +- .../java/com/indeed/util/io/Directories.java | 10 ++- .../main/java/com/indeed/util/io/Files.java | 62 +++++++++---------- .../java/com/indeed/util/io/SafeFiles.java | 26 ++++---- .../com/indeed/util/io/SafeOutputStream.java | 12 ++-- .../checkpointer/FileBasedCheckpointer.java | 14 ++--- log4j1dummyshim/build.gradle | 2 + util-core/build.gradle | 4 +- .../java/com/indeed/util/core/NetUtils.java | 10 +-- .../main/java/com/indeed/util/core/Pair.java | 16 ++--- .../com/indeed/util/core/ReleaseVersion.java | 3 +- .../java/com/indeed/util/core/TreeTimer.java | 11 ++-- .../com/indeed/util/core/io/Closeables2.java | 24 +++---- .../nullsafety/FieldsAreNonnullByDefault.java | 15 ++--- .../core/nullsafety/NonnullByDefault.java | 21 +++++++ .../ParametersAreNonnullByDefault.java | 21 +++++++ .../ReturnValuesAreNonnullByDefault.java | 17 ++--- .../core/reference/AtomicSharedReference.java | 2 +- .../reference/ReloadableSharedReference.java | 2 +- .../util/core/reference/SharedReference.java | 2 +- .../indeed/util/core/sort/Quicksortables.java | 4 +- .../util/core/threads/ThreadSafeBitSet.java | 3 +- .../util/core/time/DefaultWallClock.java | 4 +- .../indeed/util/core/time/StoppedClock.java | 7 ++- varexport/build.gradle | 2 +- .../indeed/util/varexport/VarExporter.java | 8 +-- .../servlet/ViewExportedVariablesServlet.java | 2 +- 28 files changed, 177 insertions(+), 132 deletions(-) create mode 100644 util-core/src/main/java/com/indeed/util/core/nullsafety/NonnullByDefault.java create mode 100644 util-core/src/main/java/com/indeed/util/core/nullsafety/ParametersAreNonnullByDefault.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d5b1f53..fadce4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,9 +2,9 @@ slf4jApi = "org.slf4j:slf4j-api:1.7.32" junit = "junit:junit:4.8.2" guava = "com.google.guava:guava:20.0" -jsr305 = "com.google.code.findbugs:jsr305:1.3.9" servletApi = "org.apache.tomcat:tomcat-servlet-api:7.0.8" freemarker = "org.freemarker:freemarker:2.3.16" easymock = "org.easymock:easymock:4.1" commonsLang = "commons-lang:commons-lang:2.6" hamcrest = "org.hamcrest:hamcrest-core:2.2" +checkerQual = "org.checkerframework:checker-qual:3.42.0" diff --git a/io/build.gradle b/io/build.gradle index c067948..c124491 100644 --- a/io/build.gradle +++ b/io/build.gradle @@ -6,13 +6,12 @@ dependencies { implementation project(':util-core') implementation libs.guava implementation libs.slf4jApi + api libs.checkerQual // This is a fake copy of the log4j1 Logger, which allows us to continue // accepting it in our deprecated method signatures without accidentially using // any of its functionality. compileOnly project(':log4j1dummyshim') - compileOnly libs.jsr305 - testImplementation libs.junit } diff --git a/io/src/main/java/com/indeed/util/io/Directories.java b/io/src/main/java/com/indeed/util/io/Directories.java index f3cdaf9..7dffeee 100644 --- a/io/src/main/java/com/indeed/util/io/Directories.java +++ b/io/src/main/java/com/indeed/util/io/Directories.java @@ -2,9 +2,8 @@ package com.indeed.util.io; import com.google.common.collect.Iterables; +import org.checkerframework.checker.nullness.qual.NonNull; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; import java.io.IOException; import java.nio.file.DirectoryIteratorException; import java.nio.file.DirectoryStream; @@ -26,8 +25,7 @@ public final class Directories { * @return number of inodes under it. * @throws IOException */ - @Nonnegative - public static int count(@Nonnull final Path dir) throws IOException { + public static int count(@NonNull final Path dir) throws IOException { try (final DirectoryStream stream = Files.newDirectoryStream(dir)) { return Iterables.size(stream); } catch (DirectoryIteratorException ex) { @@ -48,8 +46,8 @@ public static int count(@Nonnull final Path dir) throws IOException { * @return all files in that directory * @throws IOException */ - @Nonnull - public static List list(@Nonnull final Path dir) throws IOException { + @NonNull + public static List list(@NonNull final Path dir) throws IOException { final List contents = new ArrayList<>(); try (final DirectoryStream stream = Files.newDirectoryStream(dir)) { for (final Path entry : stream) { diff --git a/io/src/main/java/com/indeed/util/io/Files.java b/io/src/main/java/com/indeed/util/io/Files.java index 62f9c3b..5b83316 100644 --- a/io/src/main/java/com/indeed/util/io/Files.java +++ b/io/src/main/java/com/indeed/util/io/Files.java @@ -5,10 +5,10 @@ import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.hash.Hashing; +import org.checkerframework.checker.nullness.qual.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nonnull; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -67,7 +67,7 @@ public static String buildPath(String... parts) { * be written, flushed, synced, or closed */ public static void writeObjectToFileOrDie2( - @Nonnull final Object obj, @Nonnull final String file) throws IOException { + @NonNull final Object obj, @NonNull final String file) throws IOException { Preconditions.checkNotNull(file, "file argument is required!"); Preconditions.checkArgument(!file.isEmpty(), "file argument is required!"); @@ -106,18 +106,18 @@ public static void writeObjectToFileOrDie2( /** @deprecated Use {@link #writeObjectToFileOrDie2(java.lang.Object, java.lang.String)} */ @Deprecated public static void writeObjectToFileOrDie( - @Nonnull final Object obj, - @Nonnull final String file, - @Nonnull final org.apache.log4j.Logger log) + @NonNull final Object obj, + @NonNull final String file, + final org.apache.log4j.@NonNull Logger log) throws IOException { writeObjectToFileOrDie2(obj, file); } private static class ObjectOutputStreamCallback implements OutputStreamCallback { private long checksumForWrittenData = 0L; - @Nonnull private final Object obj; + @NonNull private final Object obj; - private ObjectOutputStreamCallback(@Nonnull Object obj) { + private ObjectOutputStreamCallback(@NonNull Object obj) { this.obj = obj; } @@ -126,7 +126,7 @@ public long getChecksumValue() { } @Override - public void writeAndFlushData(@Nonnull OutputStream outputStream) throws IOException { + public void writeAndFlushData(@NonNull OutputStream outputStream) throws IOException { final ChecksummingOutputStream checksummingOutputStream = new ChecksummingOutputStream(new BufferedOutputStream(outputStream)); final ObjectOutputStream out = new ObjectOutputStream(checksummingOutputStream); @@ -141,7 +141,7 @@ public void writeAndFlushData(@Nonnull OutputStream outputStream) throws IOExcep } private static class ChecksummingOutputStream extends FilterOutputStream { - @Nonnull private final Checksum checksummer; + @NonNull private final Checksum checksummer; private ChecksummingOutputStream(OutputStream out) { super(out); @@ -177,13 +177,13 @@ public long getChecksumValue() { } private static interface OutputStreamCallback { - void writeAndFlushData(@Nonnull final OutputStream outputStream) throws IOException; + void writeAndFlushData(@NonNull final OutputStream outputStream) throws IOException; } // return a reference to a temp file that contains the written + flushed + fsynced + closed data - @Nonnull + @NonNull private static File writeDataToTempFileOrDie2( - @Nonnull final OutputStreamCallback callback, @Nonnull final File targetFile) + @NonNull final OutputStreamCallback callback, @NonNull final File targetFile) throws IOException { Preconditions.checkNotNull(callback, "callback argument is required!"); Preconditions.checkNotNull(targetFile, "targetFile argument is required!"); @@ -229,18 +229,18 @@ private static File writeDataToTempFileOrDie2( * java.io.File)} */ @Deprecated - @Nonnull + @NonNull private static File writeDataToTempFileOrDie( - @Nonnull final OutputStreamCallback callback, - @Nonnull final File targetFile, - @Nonnull final org.apache.log4j.Logger log) + @NonNull final OutputStreamCallback callback, + @NonNull final File targetFile, + final org.apache.log4j.@NonNull Logger log) throws IOException { return writeDataToTempFileOrDie2(callback, targetFile); } - @Nonnull + @NonNull private static File writeTextToTempFileOrDie2( - @Nonnull final String[] text, @Nonnull final File targetFile) throws IOException { + @NonNull final String[] text, @NonNull final File targetFile) throws IOException { Preconditions.checkNotNull(text, "callback argument is required!"); Preconditions.checkNotNull(targetFile, "targetFile argument is required!"); @@ -275,11 +275,11 @@ private static File writeTextToTempFileOrDie2( /** @deprecated Use {@link #writeTextToTempFileOrDie2(java.lang.String[], java.io.File)} */ @Deprecated - @Nonnull + @NonNull private static File writeTextToTempFileOrDie( - @Nonnull final String[] text, - @Nonnull final File targetFile, - @Nonnull final org.apache.log4j.Logger log) + @NonNull final String[] text, + @NonNull final File targetFile, + final org.apache.log4j.@NonNull Logger log) throws IOException { return writeTextToTempFileOrDie2(text, targetFile); } @@ -297,7 +297,7 @@ private static File writeTextToTempFileOrDie( * synced, or closed */ public static boolean writeObjectIfChangedOrDie2( - @Nonnull final Object obj, @Nonnull final String file) throws IOException { + @NonNull final Object obj, @NonNull final String file) throws IOException { Preconditions.checkNotNull(file, "file argument is required!"); Preconditions.checkArgument(!file.isEmpty(), "file argument is required!"); @@ -364,15 +364,15 @@ public static boolean writeObjectIfChangedOrDie2( /** @deprecated Use {@link #writeObjectIfChangedOrDie2(java.lang.Object, java.lang.String)} */ @Deprecated public static boolean writeObjectIfChangedOrDie( - @Nonnull final Object obj, - @Nonnull final String file, - @Nonnull final org.apache.log4j.Logger log) + @NonNull final Object obj, + @NonNull final String file, + final org.apache.log4j.@NonNull Logger log) throws IOException { return writeObjectIfChangedOrDie2(obj, file); } public static long computeFileChecksum( - @Nonnull final File file, @Nonnull final Checksum checksum) throws IOException { + @NonNull final File file, @NonNull final Checksum checksum) throws IOException { return com.google.common.io.Files.asByteSource(file).hash(Hashing.crc32()).padToLong(); } @@ -694,7 +694,7 @@ public static void writeToTextFile(String[] lines, String file) { } public static void writeToTextFileOrDie( - @Nonnull final String[] lines, @Nonnull final String file) throws IOException { + @NonNull final String[] lines, @NonNull final String file) throws IOException { // Write out a temp file (or die) final File f = new File(file); final File temp = writeTextToTempFileOrDie2(lines, f); @@ -778,7 +778,7 @@ public static boolean delete(String file) { * @return true if all deletions were successful, false if file did not exist * @throws IOException if deletion fails and the file still exists at the end */ - public static boolean deleteOrDie(@Nonnull final String file) throws IOException { + public static boolean deleteOrDie(@NonNull final String file) throws IOException { // this returns true if the file was actually deleted // and false for 2 cases: // 1. file did not exist to start with @@ -893,8 +893,8 @@ public static String getFileHash(final String file, final String algorithm) * Converts a byte array to a hex string. The String returned will be of length exactly {@code * bytes.length * 2}. */ - @Nonnull - public static String toHex(@Nonnull final byte[] bytes) { + @NonNull + public static String toHex(@NonNull final byte[] bytes) { StringBuilder buf = new StringBuilder(bytes.length * 2); for (byte b : bytes) { String hexDigits = Integer.toHexString((int) b & 0x00ff); diff --git a/io/src/main/java/com/indeed/util/io/SafeFiles.java b/io/src/main/java/com/indeed/util/io/SafeFiles.java index 5a68941..04fc69e 100644 --- a/io/src/main/java/com/indeed/util/io/SafeFiles.java +++ b/io/src/main/java/com/indeed/util/io/SafeFiles.java @@ -4,13 +4,11 @@ import com.google.common.base.Charsets; import com.google.common.base.Throwables; import com.indeed.util.core.io.Closeables2; +import com.indeed.util.core.nullsafety.ParametersAreNonnullByDefault; +import org.checkerframework.checker.nullness.qual.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import javax.annotation.ParametersAreNonnullByDefault; -import javax.annotation.concurrent.NotThreadSafe; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -93,7 +91,6 @@ public static void ensureDirectoryExists(final Path path) throws IOException { * @return number of NormalFiles fsynced (not including directories). * @throws IOException in the event that we could not fsync the provided directory. */ - @Nonnegative public static int fsyncRecursive(final Path root) throws IOException { final FsyncingSimpleFileVisitor visitor = new FsyncingSimpleFileVisitor(); Files.walkFileTree(root, visitor); @@ -101,9 +98,8 @@ public static int fsyncRecursive(final Path root) throws IOException { } private static class FsyncingSimpleFileVisitor extends SimpleFileVisitor { - @Nonnegative private int fileCount = 0; + private int fileCount = 0; - @Nonnegative public int getFileCount() { return fileCount; } @@ -214,7 +210,7 @@ public static void write(final byte[] data, final Path path) throws IOException * @return handle to opened temp file * @throws IOException in the event that the file could not be created. */ - @Nonnull + @NonNull public static SafeOutputStream createAtomicFile(final Path path) throws IOException { final Path dir = path.getParent(); final Path name = path.getFileName(); @@ -264,15 +260,17 @@ public static void deleteIfExistsQuietly(final Path path) { } } - /** @see SafeFiles#createAtomicFile(Path) */ + /** + * @see SafeFiles#createAtomicFile(Path) + *

NotThreadSafe + */ @ParametersAreNonnullByDefault - @NotThreadSafe private static class SafeFileOutputStream extends SafeOutputStream { - @Nonnull private final Path path; - @Nonnull private final Path tempFile; + @NonNull private final Path path; + @NonNull private final Path tempFile; - @Nonnull private final OutputStream out; // do not close this - @Nonnull private final FileChannel fileChannel; // only close this + @NonNull private final OutputStream out; // do not close this + @NonNull private final FileChannel fileChannel; // only close this private boolean closed = false; diff --git a/io/src/main/java/com/indeed/util/io/SafeOutputStream.java b/io/src/main/java/com/indeed/util/io/SafeOutputStream.java index 78f7bdc..042681b 100644 --- a/io/src/main/java/com/indeed/util/io/SafeOutputStream.java +++ b/io/src/main/java/com/indeed/util/io/SafeOutputStream.java @@ -1,8 +1,8 @@ // Copyright 2015 Indeed package com.indeed.util.io; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; @@ -10,8 +10,10 @@ import java.nio.channels.WritableByteChannel; import java.nio.file.Path; -/** @see SafeFiles#createAtomicFile(Path) */ -@NotThreadSafe +/** + * @see SafeFiles#createAtomicFile(Path) + *

Not Thread Safe + */ public abstract class SafeOutputStream extends OutputStream implements WritableByteChannel, Closeable { /** @@ -25,7 +27,7 @@ public abstract class SafeOutputStream extends OutputStream * @throws IOException in the event that the buffer could not be written. */ @Override - public abstract int write(@Nonnull final ByteBuffer src) throws IOException; + public abstract int write(@NonNull final ByteBuffer src) throws IOException; /** * Commit causes the current atomic file writing operation to conclude and the current temp file diff --git a/io/src/main/java/com/indeed/util/io/checkpointer/FileBasedCheckpointer.java b/io/src/main/java/com/indeed/util/io/checkpointer/FileBasedCheckpointer.java index c5ba276..7966811 100644 --- a/io/src/main/java/com/indeed/util/io/checkpointer/FileBasedCheckpointer.java +++ b/io/src/main/java/com/indeed/util/io/checkpointer/FileBasedCheckpointer.java @@ -4,8 +4,8 @@ import com.google.common.base.Preconditions; import com.indeed.util.io.BufferedFileDataOutputStream; import com.indeed.util.serialization.Stringifier; +import org.checkerframework.checker.nullness.qual.NonNull; -import javax.annotation.Nonnull; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -23,17 +23,17 @@ public class FileBasedCheckpointer implements Checkpointer { private volatile T value; public FileBasedCheckpointer( - @Nonnull final File checkpointFile, - @Nonnull Stringifier stringifier, - @Nonnull T defaultValue) + @NonNull final File checkpointFile, + @NonNull Stringifier stringifier, + @NonNull T defaultValue) throws IOException { this(checkpointFile.toPath(), stringifier, defaultValue); } public FileBasedCheckpointer( - @Nonnull final Path checkpointFilePath, - @Nonnull Stringifier stringifier, - @Nonnull T defaultValue) + @NonNull final Path checkpointFilePath, + @NonNull Stringifier stringifier, + @NonNull T defaultValue) throws IOException { this.checkpointFilePath = Preconditions.checkNotNull(checkpointFilePath, "no checkpoint file"); diff --git a/log4j1dummyshim/build.gradle b/log4j1dummyshim/build.gradle index 075ba3d..15b6148 100644 --- a/log4j1dummyshim/build.gradle +++ b/log4j1dummyshim/build.gradle @@ -1,3 +1,5 @@ plugins { id 'java' } + +indeedOss.activateFeature 'java' diff --git a/util-core/build.gradle b/util-core/build.gradle index 1337bd3..68b9f1f 100644 --- a/util-core/build.gradle +++ b/util-core/build.gradle @@ -5,14 +5,12 @@ dependencies { implementation project(':varexport') implementation libs.guava implementation libs.slf4jApi + api libs.checkerQual // This is a fake copy of the log4j1 Logger, which allows us to continue // accepting it in our deprecated method signatures without accidentially using // any of its functionality. compileOnly project(':log4j1dummyshim') - compileOnly libs.jsr305 - testCompileOnly libs.jsr305 - testImplementation libs.junit } diff --git a/util-core/src/main/java/com/indeed/util/core/NetUtils.java b/util-core/src/main/java/com/indeed/util/core/NetUtils.java index ccb5b01..3261a74 100644 --- a/util-core/src/main/java/com/indeed/util/core/NetUtils.java +++ b/util-core/src/main/java/com/indeed/util/core/NetUtils.java @@ -2,11 +2,11 @@ import com.google.common.base.Optional; import com.google.common.base.Strings; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; @@ -33,7 +33,7 @@ public class NetUtils { * @return hostname * @throws java.net.UnknownHostException unable to lookup a host name correctly */ - @Nonnull + @NonNull public static String determineHostName() throws UnknownHostException { if (!OPT_HOSTNAME.isPresent()) { final String hostName = InetAddress.getLocalHost().getHostName(); @@ -58,8 +58,8 @@ public static String determineHostName() throws UnknownHostException { * @param defaultValue The default hostname to use in the event one is not preset. * @return The detected hostname if present, or the default value. */ - @Nonnull - public static String determineHostName(@Nonnull final String defaultValue) { + @NonNull + public static String determineHostName(@NonNull final String defaultValue) { checkNotNull(defaultValue, "Unable to use default value of null for hostname"); if (!OPT_HOSTNAME.isPresent()) { try { diff --git a/util-core/src/main/java/com/indeed/util/core/Pair.java b/util-core/src/main/java/com/indeed/util/core/Pair.java index 17662e5..432ff04 100644 --- a/util-core/src/main/java/com/indeed/util/core/Pair.java +++ b/util-core/src/main/java/com/indeed/util/core/Pair.java @@ -1,9 +1,9 @@ package com.indeed.util.core; import com.google.common.base.Function; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.Serializable; import java.util.Comparator; @@ -82,10 +82,10 @@ public int compare(Pair o1, Pair o2) { * @return a Function that returns null or the first value of the Pair, which also may be null * @deprecated use {@link #fst()}. */ - @Nonnull + @NonNull @Deprecated public static Function, ? extends T1> fst( - @Nonnull final Class clazz) { + @NonNull final Class clazz) { return new First<>(); } @@ -108,7 +108,7 @@ public T1 apply(@Nullable Pair input) { * @param The expected data type of {@link Pair#a} * @return a Function that returns null or the first value of the Pair, which also may be null */ - @Nonnull + @NonNull public static Function, ? extends T> fst() { return new Function, T>() { @Nullable @@ -131,10 +131,10 @@ public T apply(@Nullable Pair input) { * @param Expected data type for {@link Pair#b} * @return A function that returns null or the second value of the Pair, which also may be null */ - @Nonnull + @NonNull @Deprecated public static Function, ? extends T2> snd( - @Nonnull final Class clazz) { + @NonNull final Class clazz) { return new Second<>(); } @@ -157,7 +157,7 @@ public T2 apply(@Nullable Pair input) { * @param The expected data type for {@link Pair#b}. * @return a Function that returns null or the second value of the Pair, which also may be null */ - @Nonnull + @NonNull public static Function, ? extends T> snd() { return new Function, T>() { @Nullable diff --git a/util-core/src/main/java/com/indeed/util/core/ReleaseVersion.java b/util-core/src/main/java/com/indeed/util/core/ReleaseVersion.java index feb8968..918f8c0 100644 --- a/util-core/src/main/java/com/indeed/util/core/ReleaseVersion.java +++ b/util-core/src/main/java/com/indeed/util/core/ReleaseVersion.java @@ -1,6 +1,7 @@ package com.indeed.util.core; -import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Arrays; /** diff --git a/util-core/src/main/java/com/indeed/util/core/TreeTimer.java b/util-core/src/main/java/com/indeed/util/core/TreeTimer.java index ddc7093..84e7d70 100644 --- a/util-core/src/main/java/com/indeed/util/core/TreeTimer.java +++ b/util-core/src/main/java/com/indeed/util/core/TreeTimer.java @@ -1,6 +1,7 @@ package com.indeed.util.core; -import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.util.LinkedHashMap; import java.util.Map; import java.util.Stack; @@ -79,8 +80,8 @@ private static void printNode(int indent, Node n, StringBuilder ret) { * Left-pads a String with spaces so it is length n. If the String is already at * least length n, no padding is done. */ - @Nonnull - private static String leftpad(@Nonnull String s, int n) { + @NonNull + private static String leftpad(@NonNull String s, int n) { return leftpad(s, n, ' '); } @@ -88,8 +89,8 @@ private static String leftpad(@Nonnull String s, int n) { * Left-pads a String with the specific padChar so it is length n. If the String is * already at least length n, no padding is done. */ - @Nonnull - private static String leftpad(@Nonnull String s, int n, char padChar) { + @NonNull + private static String leftpad(@NonNull String s, int n, char padChar) { int diff = n - s.length(); if (diff <= 0) { return s; diff --git a/util-core/src/main/java/com/indeed/util/core/io/Closeables2.java b/util-core/src/main/java/com/indeed/util/core/io/Closeables2.java index 6dc7be6..7eb6eed 100644 --- a/util-core/src/main/java/com/indeed/util/core/io/Closeables2.java +++ b/util-core/src/main/java/com/indeed/util/core/io/Closeables2.java @@ -1,11 +1,11 @@ package com.indeed.util.core.io; import com.google.common.base.Throwables; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.Closeable; import java.util.Arrays; @@ -36,7 +36,7 @@ public static void close(@Nullable final Closeable closeable) { /** @deprecated Use {@link #close(java.io.Closeable)} */ @Deprecated public static void closeQuietly( - @Nullable final Closeable closeable, @Nonnull final org.apache.log4j.Logger log) { + @Nullable final Closeable closeable, final org.apache.log4j.@NonNull Logger log) { close(closeable); } @@ -46,7 +46,7 @@ public static void closeQuietly( * * @param closeables The closeables that we want to close. */ - public static void close(@Nonnull final Iterable closeables) { + public static void close(@NonNull final Iterable closeables) { Throwable throwable = null; for (Closeable closeable : closeables) { try { @@ -67,8 +67,8 @@ public static void close(@Nonnull final Iterable closeables /** @deprecated Use {@link #close(java.lang.Iterable)} */ @Deprecated public static void closeAll( - @Nonnull final Iterable closeables, - @Nonnull final org.apache.log4j.Logger log) { + @NonNull final Iterable closeables, + final org.apache.log4j.@NonNull Logger log) { close(closeables); } @@ -78,22 +78,22 @@ public static void closeAll( * * @param closeables The closeables that we want to close. */ - public static void close(@Nonnull final Closeable... closeables) { + public static void close(@NonNull final Closeable... closeables) { close(Arrays.asList(closeables)); } /** @deprecated Use {@link #close(java.io.Closeable...)} */ @Deprecated public static void closeAll( - @Nonnull final org.apache.log4j.Logger log, @Nonnull final Closeable... closeables) { + final org.apache.log4j.@NonNull Logger log, @NonNull final Closeable... closeables) { close(closeables); } /** @deprecated Use {@link #close(java.io.Closeable...)} */ @Deprecated public static void closeAll( - @Nonnull final org.apache.log4j.Logger log, - @Nonnull final Iterable closeables) { + final org.apache.log4j.@NonNull Logger log, + @NonNull final Iterable closeables) { close(closeables); } @@ -111,7 +111,7 @@ public static void closeAll( */ @Deprecated public static Closeable forIterable( - @Nonnull final org.apache.log4j.Logger log, @Nonnull final Iterable closeables) { + final org.apache.log4j.@NonNull Logger log, @NonNull final Iterable closeables) { return () -> close(closeables); } @@ -128,7 +128,7 @@ public static Closeable forIterable( */ @Deprecated public static Closeable forArray( - @Nonnull final org.apache.log4j.Logger log, @Nonnull final Closeable... closeables) { + final org.apache.log4j.@NonNull Logger log, @NonNull final Closeable... closeables) { return () -> close(closeables); } } diff --git a/util-core/src/main/java/com/indeed/util/core/nullsafety/FieldsAreNonnullByDefault.java b/util-core/src/main/java/com/indeed/util/core/nullsafety/FieldsAreNonnullByDefault.java index 49c60af..347e3d7 100644 --- a/util-core/src/main/java/com/indeed/util/core/nullsafety/FieldsAreNonnullByDefault.java +++ b/util-core/src/main/java/com/indeed/util/core/nullsafety/FieldsAreNonnullByDefault.java @@ -1,20 +1,21 @@ package com.indeed.util.core.nullsafety; -import javax.annotation.Nonnull; -import javax.annotation.meta.TypeQualifierDefault; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.checkerframework.framework.qual.TypeUseLocation; + import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Annotation for types or packages which assumes all member variables are @Nonnull unless indicated - * otherwise with @Nullable + * otherwise with {@link org.checkerframework.checker.nullness.qual.Nullable} * - * @author rboyer + * @deprecated Use {@link NonnullByDefault} */ +@Deprecated @Documented -@Nonnull -@TypeQualifierDefault({ElementType.FIELD}) +@DefaultQualifier(value = NonNull.class, locations = TypeUseLocation.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FieldsAreNonnullByDefault {} diff --git a/util-core/src/main/java/com/indeed/util/core/nullsafety/NonnullByDefault.java b/util-core/src/main/java/com/indeed/util/core/nullsafety/NonnullByDefault.java new file mode 100644 index 0000000..306e672 --- /dev/null +++ b/util-core/src/main/java/com/indeed/util/core/nullsafety/NonnullByDefault.java @@ -0,0 +1,21 @@ +package com.indeed.util.core.nullsafety; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.checkerframework.framework.qual.TypeUseLocation; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation for types or packages which assumes all parameters, member variables, and return + * values are @Nonnull unless indicated otherwise with {@link + * org.checkerframework.checker.nullness.qual.Nullable} + */ +@Documented +@DefaultQualifier( + value = NonNull.class, + locations = {TypeUseLocation.FIELD, TypeUseLocation.RETURN, TypeUseLocation.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NonnullByDefault {} diff --git a/util-core/src/main/java/com/indeed/util/core/nullsafety/ParametersAreNonnullByDefault.java b/util-core/src/main/java/com/indeed/util/core/nullsafety/ParametersAreNonnullByDefault.java new file mode 100644 index 0000000..d79629a --- /dev/null +++ b/util-core/src/main/java/com/indeed/util/core/nullsafety/ParametersAreNonnullByDefault.java @@ -0,0 +1,21 @@ +package com.indeed.util.core.nullsafety; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.checkerframework.framework.qual.TypeUseLocation; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation for types or packages which warns if null is passed as a parameter to a method, if the + * parameter is not annotated with {@link org.checkerframework.checker.nullness.qual.Nullable} + * + * @deprecated Use {@link NonnullByDefault} + */ +@Deprecated +@Documented +@DefaultQualifier(value = NonNull.class, locations = TypeUseLocation.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface ParametersAreNonnullByDefault {} diff --git a/util-core/src/main/java/com/indeed/util/core/nullsafety/ReturnValuesAreNonnullByDefault.java b/util-core/src/main/java/com/indeed/util/core/nullsafety/ReturnValuesAreNonnullByDefault.java index 90ea5a3..feb27c3 100644 --- a/util-core/src/main/java/com/indeed/util/core/nullsafety/ReturnValuesAreNonnullByDefault.java +++ b/util-core/src/main/java/com/indeed/util/core/nullsafety/ReturnValuesAreNonnullByDefault.java @@ -1,18 +1,21 @@ package com.indeed.util.core.nullsafety; -import javax.annotation.Nonnull; -import javax.annotation.meta.TypeQualifierDefault; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.checkerframework.framework.qual.TypeUseLocation; + import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * @author jplaisance annotation for types or packages which warns if null is returned from a method - * not annotated with @Nullable + * Annotation for types or packages which warns if null is returned from a method not annotated with + * {@link org.checkerframework.checker.nullness.qual.Nullable} + * + * @deprecated Use {@link NonnullByDefault} */ +@Deprecated @Documented -@Nonnull -@TypeQualifierDefault(ElementType.METHOD) +@DefaultQualifier(value = NonNull.class, locations = TypeUseLocation.RETURN) @Retention(RetentionPolicy.RUNTIME) public @interface ReturnValuesAreNonnullByDefault {} diff --git a/util-core/src/main/java/com/indeed/util/core/reference/AtomicSharedReference.java b/util-core/src/main/java/com/indeed/util/core/reference/AtomicSharedReference.java index 64fe170..fba003d 100644 --- a/util-core/src/main/java/com/indeed/util/core/reference/AtomicSharedReference.java +++ b/util-core/src/main/java/com/indeed/util/core/reference/AtomicSharedReference.java @@ -2,10 +2,10 @@ import com.google.common.base.Function; import com.indeed.util.core.io.Closeables2; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; import java.io.Closeable; import java.io.IOException; diff --git a/util-core/src/main/java/com/indeed/util/core/reference/ReloadableSharedReference.java b/util-core/src/main/java/com/indeed/util/core/reference/ReloadableSharedReference.java index 426e846..b8b00d1 100644 --- a/util-core/src/main/java/com/indeed/util/core/reference/ReloadableSharedReference.java +++ b/util-core/src/main/java/com/indeed/util/core/reference/ReloadableSharedReference.java @@ -2,10 +2,10 @@ import com.google.common.base.Supplier; import com.indeed.util.core.io.Closeables2; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; import java.io.Closeable; import java.io.IOException; diff --git a/util-core/src/main/java/com/indeed/util/core/reference/SharedReference.java b/util-core/src/main/java/com/indeed/util/core/reference/SharedReference.java index d01da62..9e3a604 100644 --- a/util-core/src/main/java/com/indeed/util/core/reference/SharedReference.java +++ b/util-core/src/main/java/com/indeed/util/core/reference/SharedReference.java @@ -1,9 +1,9 @@ package com.indeed.util.core.reference; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; import java.io.Closeable; import java.io.IOException; diff --git a/util-core/src/main/java/com/indeed/util/core/sort/Quicksortables.java b/util-core/src/main/java/com/indeed/util/core/sort/Quicksortables.java index 85098a6..d064e2e 100644 --- a/util-core/src/main/java/com/indeed/util/core/sort/Quicksortables.java +++ b/util-core/src/main/java/com/indeed/util/core/sort/Quicksortables.java @@ -2,8 +2,8 @@ import com.google.common.primitives.Booleans; import com.google.common.primitives.Ints; +import org.checkerframework.checker.nullness.qual.NonNull; -import javax.annotation.Nonnull; import java.util.Random; /** @author ahudson */ @@ -51,7 +51,7 @@ public int compare(int a, int b) { } public static Quicksortable getQuicksortableParallelArrays( - @Nonnull final long[] array1, @Nonnull final int[] array2) { + final long @NonNull [] array1, final int @NonNull [] array2) { return new Quicksortable() { public void swap(int i, int j) { Quicksortables.swap(array1, i, j); diff --git a/util-core/src/main/java/com/indeed/util/core/threads/ThreadSafeBitSet.java b/util-core/src/main/java/com/indeed/util/core/threads/ThreadSafeBitSet.java index 4ae275c..ea44e36 100644 --- a/util-core/src/main/java/com/indeed/util/core/threads/ThreadSafeBitSet.java +++ b/util-core/src/main/java/com/indeed/util/core/threads/ThreadSafeBitSet.java @@ -1,6 +1,7 @@ package com.indeed.util.core.threads; -import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.Serializable; import java.util.Arrays; diff --git a/util-core/src/main/java/com/indeed/util/core/time/DefaultWallClock.java b/util-core/src/main/java/com/indeed/util/core/time/DefaultWallClock.java index a67bf73..4c8d545 100644 --- a/util-core/src/main/java/com/indeed/util/core/time/DefaultWallClock.java +++ b/util-core/src/main/java/com/indeed/util/core/time/DefaultWallClock.java @@ -1,14 +1,12 @@ package com.indeed.util.core.time; -import javax.annotation.concurrent.ThreadSafe; - /** * Default {@link WallClock} implementation using system current time. * * @deprecated with {@link WallClock}. Use an instance of {@link java.time.Clock} instead. * @author patrick@indeed.com + *

ThreadSafe */ -@ThreadSafe public class DefaultWallClock implements WallClock { @Override public long currentTimeMillis() { diff --git a/util-core/src/main/java/com/indeed/util/core/time/StoppedClock.java b/util-core/src/main/java/com/indeed/util/core/time/StoppedClock.java index 86c1178..01d3dfc 100644 --- a/util-core/src/main/java/com/indeed/util/core/time/StoppedClock.java +++ b/util-core/src/main/java/com/indeed/util/core/time/StoppedClock.java @@ -1,6 +1,7 @@ package com.indeed.util.core.time; -import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.time.Instant; import java.time.ZoneId; import java.util.concurrent.TimeUnit; @@ -14,7 +15,7 @@ */ @Deprecated public final class StoppedClock implements WallClock { - @Nonnull private final AtomicLong millis; + @NonNull private final AtomicLong millis; /** Creates a new stopped clock frozen at the current moment in time. */ public StoppedClock() { @@ -47,7 +48,7 @@ public final void set(final long millis) { * @param timeUnit The time unit that {@code value} is measured in. * @return The time after being adjusted by the provided offset. */ - public final long plus(final long value, @Nonnull final TimeUnit timeUnit) { + public final long plus(final long value, @NonNull final TimeUnit timeUnit) { return this.millis.addAndGet(timeUnit.toMillis(value)); } diff --git a/varexport/build.gradle b/varexport/build.gradle index 4884e86..df1b854 100644 --- a/varexport/build.gradle +++ b/varexport/build.gradle @@ -5,7 +5,7 @@ dependencies { implementation libs.guava implementation libs.slf4jApi - compileOnly libs.jsr305 + api libs.checkerQual compileOnly libs.servletApi testImplementation libs.junit diff --git a/varexport/src/main/java/com/indeed/util/varexport/VarExporter.java b/varexport/src/main/java/com/indeed/util/varexport/VarExporter.java index 675d5a4..7118efc 100644 --- a/varexport/src/main/java/com/indeed/util/varexport/VarExporter.java +++ b/varexport/src/main/java/com/indeed/util/varexport/VarExporter.java @@ -13,11 +13,11 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.google.common.collect.Sets; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.AnnotatedElement; @@ -109,7 +109,7 @@ public static synchronized VarExporter forNamespace(String namespace) { * namespace does not exist */ public static synchronized Optional forNamespaceIfExists( - @Nonnull final String namespace) { + @NonNull final String namespace) { return Optional.ofNullable(namespaces.get(namespace)); } @@ -122,7 +122,7 @@ public static synchronized Optional forNamespaceIfExists( * @return exporter for the given class will be created if never before accessed. */ public static synchronized VarExporter forNamespace( - @Nonnull final Class clazz, final boolean declaredFieldsOnly) { + @NonNull final Class clazz, final boolean declaredFieldsOnly) { return getInstance(clazz.getSimpleName(), clazz, declaredFieldsOnly); } diff --git a/varexport/src/main/java/com/indeed/util/varexport/servlet/ViewExportedVariablesServlet.java b/varexport/src/main/java/com/indeed/util/varexport/servlet/ViewExportedVariablesServlet.java index c8600e3..2f73bc1 100644 --- a/varexport/src/main/java/com/indeed/util/varexport/servlet/ViewExportedVariablesServlet.java +++ b/varexport/src/main/java/com/indeed/util/varexport/servlet/ViewExportedVariablesServlet.java @@ -16,10 +16,10 @@ import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException;