javainputstreamfindbugs

How do I ignore all data from an InputStream without tripping up static-analysis tools?


I have an InputStream that's attached to stdout of another process. I sometimes need to log data from the stream, and sometimes don't. Even when I don't care about the output, I still need to read it so that the other process doesn't block due to a full output buffer. I use the following code to selectively log the output:

InputStream is = ...;
boolean report = ...;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
if (report) {
    String line = null;
    while ((line = br.readLine()) != null) {
        Debug.println(line);
    }
} else {
    while (br.readLine() != null) {
    }
}

However, in the second while loop, FindBugs alerts (RV_DONT_JUST_NULL_CHECK_READLINE) that I'm calling readLine and only checking whether it's null, not doing anything with the result. Its analysis is correct, but I don't want to do anything with the result in that case. Is there some idiomatic way of consuming and ignoring all data from a stream such that it might not look like a mistake to FindBugs?


Solution

  • You can avoid having to construct String objects that just get thrown away by using skip on the InputStream. (InputStreamReader and BufferedReader also have skip methods, but if you're looking to skip the entire stream, you don't really need the character-decoding features of InputStreamReader or the line-detection and buffer-management features of BufferedReader.)

    while (is.skip(Long.MAX_VALUE) == Long.MAX_VALUE) {
    }
    

    It's unlikely the loop will ever run more than once — you'd need to read 8 exabytes off the stream first — but the loop is there to quell another FindBugs warning (SR_NO_CHECKED) that happens if you call skip without inspecting the return value.


    Using the SuppressWarnings annotation to silence the compiler is ineffective because it's not the compiler that's worried about the unused return value. The annotation isn't stored in the compiled code, so byte-code analyzers like FindBugs can't see it anyway. Furthermore, none of the warnings that SuppressWarnings suppresses applies in this situation; in particular, unused doesn't apply because return values aren't among the things the compiler checks.

    Instead of the Java built-in SuppressWarnings, though, you can try using some other suppression mechanism provided by the static-analysis tool that's generating the warning. In the case of FindBugs, that's the SuppressFBWarnings annotation.

    import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    

    To minimize the scope of the warning suppression, you can isolate the warning-generating code in its own method. For example:

    @SuppressFBWarnings("RV_DONT_JUST_NULL_CHECK_READLINE")
    private void consumeWholeStream(BufferedReader br) throws IOException {
        while (br.readLine() != null) {
        }
    }
    

    Then you can use that method in the given context:

    if (report) {
        String line = null;
        while ((line = br.readLine()) != null) {
            Debug.println(line);
        }
    } else {
        consumeWholeStream(br);
    }
    

    The caveat is that this adds the FindBugs annotation jar to your build dependencies. It's not added to the program's run-time dependencies, though.