How to tell IDEA/Studio that the null check has been done? - intellij-idea

I'm developing with Android Studio/IntelliJ IDEA.
I have enabled the inspection check called "Constant conditions & exceptions" that shows a warning if I am risking a NPE, such as:
String foo = foo.bar(); // Foo#bar() is #nullable
if (foo.contains("bar")) { // I'm living dangerously
...
}
I have the following in my code:
String encoding = contentEncoding == null ? null : contentEncoding.getValue();
if (!TextUtils.isEmpty(encoding) && encoding.equalsIgnoreCase("gzip")) {
inputStream = new GZIPInputStream(entity.getContent());
} else {
inputStream = entity.getContent();
}
Here's the source code of TextUtils#isEmpty(String):
/**
* Returns true if the string is null or 0-length.
* #param str the string to be examined
* #return true if str is null or zero length
*/
public static boolean isEmpty(CharSequence str) {
if (str == null || str.length() == 0)
return true;
else
return false;
}
I'm not risking any NPE because TextUtils#isEmpty(String) would return true to a null pointer.
However I'm still getting the little Method invocation 'encoding.equalsIgnoreCase("gzip")' may produce 'java.lang.NullPointerException' warning, which can be annoying.
Is it possible to make this check smarter and ignore the NPE warning if there's already a null-check done?

You can look into the link that Peter Gromov mention in his answer.
Created some simple classes that resemble your setup:
A class with a method annotated with #Nullable:
The TextUtil class with it's isEmpty method:
And finally the main class calling the TextUtil#isEmpty:
Now if you enter the File -> Settings... and go to Inspections ->Constant conditions & exceptions part you can change the Configure Assert/Check Methods to cater for your isEmpty method:
Add a new IsNull check method:
Enter the TextUtil class, isEmpty method and CharSequence parameter:
This gives this Assert/Check Method Configuration window:
Press Ok and then Ok again to go back to the editor view and you'll see that the inspection disappeared:
You are actually telling IntelliJ that the isEmpty method is doing a null check on the str parameter.

You could use //noinspection ConstantConditions that will remove the NPE warning for the following line, like this:
String encoding = contentEncoding == null ? null : contentEncoding.getValue();
//noinspection ConstantConditions
if (!TextUtils.isEmpty(encoding) && encoding.equalsIgnoreCase("gzip")) {
inputStream = new GZIPInputStream(entity.getContent());
} else {
inputStream = entity.getContent();
}

You can use #SuppressWarnings("ConstantConditions") annotation.
#SuppressWarnings("ConstantConditions")
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int indexViewType) {
if (inflater == null) {
inflater = LayoutInflater.from(parent.getContext());
}
ItemViewProvider provider = getProviderByIndex(indexViewType);
provider.adapter = MultiTypeAdapter.this;
return provider.onCreateViewHolder(inflater, parent);
}

Select "TextUtils.isEmpty".
Right Click -> Show Context Actions -> Add Method Contract.
Enter "null -> true".
Save the configuration xml.
Please check the details here

See http://www.jetbrains.com/idea/webhelp/configuring-check-assert-methods.html for IDEA 12.
In IDEA 13 EAP, you can add method contract: http://youtrack.jetbrains.com/issue/IDEA-93372

Unfortunately marked as "right answer" solution is of date. But I found equivalent for me solution.
The new versions of IDE work correctly with static methods. So the example from the question won't throw warning anymore.
TextUtils#isEmpty(String);
public static boolean isEmpty(CharSequence str) {
// your checks
}

Related

WebFlux and null value

I have simple dto, with a field that can be null
public ResponseDto{
...
#Nullable
public List<ListDto> getListDto() {
return this.listDto;
}
...
}
How to correctly implement the check that disappeared remove the warning
#NotNull
public Flux<ListDto> getApplicationList(String applicationSubsidiesId) {
return Mono.fromCallable(() -> mapper.toRq(applicationSubsidiesId))
.subscribeOn(Schedulers.boundedElastic())
.flatMap(subsidiesClient::getResponseById)
.filter(responseDto -> Objects.nonNull(responseDto.getListDto()))
.map(ResponseDto::getListDto) <- Return null or something nullable from a lambda in transformation method
.flatMapMany(Flux::fromIterable);
}
One of my decisions - rewrite map
.map(responseDto -> Objects.requireNonNull(responseDto .getListDto()))
Are there any other options on how to correctly implement this check?
null should be Empty in a reactive context. You cannot return null from a mapper, at least not in Reactor/WebFlux.
If you need to further process all values, even if they are null, I would suggest using an optional.
The idiomatic approach in WebFlux would be to filter out unwanted values completely and the react to an empty Mono with defaultIfEmpty() or switchIfEmpty():
#NotNull
public Flux<ListDto> getApplicationList(String applicationSubsidiesId) {
final var defaultResponseDto = new ResponseDto();
return Mono.fromCallable(() -> mapper.toRq(applicationSubsidiesId))
.subscribeOn(Schedulers.boundedElastic())
.flatMap(subsidiesClient::getResponseById)
.filter(responseDto -> Objects.nonNull(responseDto.getListDto()))
// filter may cause an empty flux, in which case the next line
// will not be executed.
.flatMapMany(Flux::fromIterable)
// in case of an empty flux, this line will kick in:
.defaultIfEmpty(Flux.fromIterable(defaultResponseDto.getListDto()));
// as an alternative, you can call for a fallback:
// .switchIfEmpty(getAnotherFluxFromSomewhereElse());
}

How can I place `throw` inside helper-functions but still have null-safety?

I want to wrap a throw in a helper-function, for logging purposes and such.
private fun chooseEmailAddress(user: UserProfile): EmailAddress {
val emailAddress = user.emailAddresses.find {
true // some business logic
}
if (emailAddress == null) {
throwAndNotice(CustomError(
message = "No Email Address found.",
))
}
return emailAddress
}
private fun throwAndNotice(err: CustomError) {
NewRelic.noticeError(err)
throw err
}
The problem:kotlin complains about a type-mismatch:
Type mismatch.
Required: Email
Found: Email?
I guess the compiler does not know that throwAndNotice always throws. If I inline the throwAndNotice method, it works, but it leads to duplication in about a dozen methods.
Is there a way I can tell the compiler "the following method always throws"? Or is there another idiomatic way to deal with this issue? I don't want to resort to !!.
Make it return Nothing. This indicates that it will never return (either throw an exception or infinite loop):
private fun throwAndNotice(err: CustomError): Nothing {
NewRelic.noticeError(err)
throw err
}
You can see other examples of doing this in the standard library, like TODO() and error().
Side note (as mentioned by dey in the comments):
The null check can be rewritten using ?: like this:
return emailAddress ?: throwAndNotice(...)

Smart cast to 'Bitmap!' is impossible, because 'bitmap1' is a mutable property that could have been changed by this time

bitmap1 = Bitmap.createScaledBitmap(
bitmap1, // <---- error is here
(width.toInt()),
(height.toInt()),
false)
numberOfInvaders ++
I also used bitmap2 and bitmap 1 in another class :
if (uhOrOh) {
canvas.drawBitmap(Invader.bitmap1, // <--- error is here
invader.position.left,
invader.position.top,
paint)
} else {
canvas.drawBitmap(Invader.bitmap2, // <---- and here
invader.position.left,
invader.position.top,
paint)
}
here its says : Type mismatch,
Required:Bitmap Found: Bitmap?
Yup, that's true :) You cannot use value like this, because it can be null at some point.
createScaledBitmap requires nonnullable Bitmap, but there is no guarantee that bitmap you use won't be null at the moment of calling given function.
So, what you can do?
Before the call check if bitmap is not null:
if (bitmap != null) { /* code here, still requires !! operator */ }
In multithreaded environment there is a risk that during execution of code block a value will change anyway, so you can use let function with ?. operator (basically the same operator like ., but executes only if value is not null). The block code will be invoked with an effectively final argument which is an instance you use to call this method, in this case "bitmap", called "context object", accessible via it keyword:
bitmap?.let { /* code here, bitmap is passed as effectively final, so for sure it's not null */ }
There other way would be !! operator (but it can finish with NPE exception, if value is null). Use only if you are sure that this value at that moment won't be null, otherwise you can crash your application.
Also, you can use ?: operator - this will take first value if not null, otherwise the second. It's quite nice, because you can use for example default value. Also, you can throw exception there ;)
bitmap ?: throw IllegalStateException("bitmap is null") // exception
bitmap ?: DEFAULT_BITMAP // default bitmap, if any
In this case you will get exception but with very communicative message (instead of just NPE).
bitmap1 = Bitmap.createScaledBitmap(
bitmap1!!, // !! <--- helps
(width.toInt()),
(height.toInt()),
false)
numberOfInvaders ++
if (uhOrOh) {
canvas.drawBitmap(Invader.bitmap1!!, // here
invader.position.left,
invader.position.top,
paint)
} else {
canvas.drawBitmap(Invader.bitmap2!!, // and here too
invader.position.left,
invader.position.top,
paint)
}

Code analysis warning: CA1062 is really false positive?

In my code, I have a reference variable LogValidacionPagosDTO
public void InsertarArchivoXmlOk(ArchivoXmlDRO archivo, ref LogValidacionPagosDTO archivoRespuesta)
{
//Some code
}
When executing "code analysis" generates this warning
Warning CA1062
In externally visible method 'ArchivoXMLOperacion.ValidacionDuplicadosArchivoXmlFosyga(List<RegistroXmlFosygaDRO>, ref LogValidacionPagosDTO)',
validate local variable ''(*archivoRespuesta)'', which was reassigned from parameter 'archivoRespuesta', before using it.
Then try to validate the object as null
public void InsertarArchivoXmlOk(ArchivoXmlDRO archivo, ref LogValidacionPagosDTO archivoRespuesta)
{
if (archivoRespuesta == null || archivoRespuesta.DetalleRegistros == null)
throw new ExcepcionOperacion(HelperMensaje.Obtener(HelperCodigoMensaje.GEN_0003),
(int)CodigosHTTP.Error, archivoRespuesta, null);
//Some code
}
But this didn't solve the warning. I found this possible solution in Microsoft forum https://social.msdn.microsoft.com/Forums/en-US/fdb00899-c7ea-4e8e-b5f6-9768c2ac0001/ca1062-false-positive-in-externally-visible-method-xxx-validate-local-variable-x-which-was?forum=vstscode
But, I really need to know if this is a false positive, thks!

Can IDEA do the same if/else suggestions as Resharper?

IDEA's developers are also developers of Resharper. And I like the way Resharper suggests refactoring if/else.
Can IDEA do the same? this feature does not come by default.
EDIT
Here are some Resharper feature I am referring to:
Original code:
static public string ToNonNullString(this XmlAttribute attr)
{
if (attr != null)
return attr.Value;
else
return string.Empty;
}
Suggestion: remove redundant 'else' resulting in following:
static public string ToNonNullString(this XmlAttribute attr)
{
if (attr != null)
return attr.Value;
return string.Empty;
}
Source is here (
Code suggestions by Resharper making code less readable?).
I remember when I use Visual Studio with Resharper I get a lot of similar suggestions. Have not seen that in IDEA although I've been using it for 2 years.
Yes, it can. Using this Java code:
public class Test {
public String notNull(String str) {
if (str != null) {
return str;
} else {
return "empty";
}
}
}
I get the following suggestions when pressing Alt+Enter (Show intentions) on the else:
Selecting Remove Redundant 'else' converts the method to this:
public String notNull(String str) {
if (str != null) {
return str;
}
return "empty";
}
You can make IDEA report these automatically when you run an inspection. In Settings, go to Inspections, find Confusing 'else' branch in the Control flow-category. And check the Also report when there are no more statements after the 'if' statement.
Then running an inspection with that profile will show that you have a confusing else branch, and you can fix it with a click.