How can I annotate my helper method so that Eclipse knows its argument is not null if it returns true?

I have a helper method hasContent(String)

that returns true if its argument is non-zero and contains at least one non-whitespace character. I just enabled null parsing in Eclipse, and I found that when I use this method to execute a block of code that is conditioned by the result of my helper function indicating that the string has content (and therefore cannot be null), the less Eclipse complains that my String can still be null.

Helper function

public static boolean hasContent(String text) {
    if (text == null)
        return false;
    if (text.trim().length() == 0)
        return false;
    return true;
}

      

Usage example

...
String dataString;

try {
    dataString = readStringFromFile("somefile.txt");
} catch (IOException e) {
    System.err.println("Failed to read file due to error: " + e);
    dataString = null;
}

// At this point dataString may be null

if (hasContent(dataString)) {

    // At this point dataString must be non-null, but Eclipse warns:
    // "Potential null pointer access: The variable dataString may be null at this location"
    // at the following reference to dataString

    System.out.println("Read string length " + dataString.length());
}
...

      

What's the best practice for this situation? I don't want to suppress the warning if I can avoid it. I would rather tell Eclipse that if it does hasContent()

return true

then the argument is definitely not null. Is it possible? If so, how?

+3


source to share


3 answers


The contract of your method is that if it hasContent

returns true, then its argument is guaranteed to be non-null.

Eclipse cannot express or verify this contract at compile time, at least not without changing the code and degrading its style.

Nullness Checker is another tool that can express and check this contract at compile time. It does this without requiring you to change your code. You just add @EnsuresNonNullIf

code annotation:



@EnsuresNonNullIf(expression="#1", result=true)
public static boolean hasContent(String text) { ...

      

The Nullness Checker Controller is distributed with the Checker Framework . There is an Eclipse plugin that allows you to run the Nullness Checker in Eclipse.

+3


source


This may not be the best practice, but: If an IOException is thrown, you can return false, or simply set the variable to false. If not, you can set the variable to true (in a try block).



try {
    dataString = readStringFromFile("somefile.txt");
    hasContent = true;
} catch (IOException e) {
    System.err.println("Failed to read file due to error: " + e);
    hasContent = false;
}

      

0


source


I see no way to do what you are trying to do.

You can change hasContent

to return the passed string, not a boolean

, and throw Exception

if the argument is empty or empty. Then you have to annotate the function with @NonNull

. This, however, will compromise your calling code in a way that I suspect you will not like, as it will have to use the logic try

/ catch

and not if

.

This will make the function hasContent

:

@NonNull
public static String hasContent(String text) throws Exception {
    if (text == null)
        throw new Exception( "Null string" );
    if (text.trim().length() == 0)
        throw new Exception( "Empty string" );
    return text;        
}

      

and the calling code:

...
try {
    dataString = readStringFromFile("somefile.txt");
} catch (IOException e) {
    System.err.println("Failed to read file due to error: " + e);
    dataString = null;
}

// At this point dataString may be null
try {
    dataString = validateHasContent( dataString );
    // At this point dataString must be non-null

    System.out.println("Read string length " + dataString.length());
} catch( Exception e ) {        
}
...

      

If you were willing to make this compromise, then a special exception would clearly be better.

0


source







All Articles