I would like to use FindBugs to create a report about an application.
I run it and it doesn't find a potential bug like this:
public List<String> getListTrace(A object) {
String arg = object.getArg();
...
}
If object is null, my application will be down.
Why FindBugs doesn't raise an alert?
Findbugs doesn't know if object is allowed to be null or not. You can tell it by using annotations:
import javax.annotation.Nullable;
...
public List<String> getListTrace(#Nullable A object) {
This tells Findbugs (and people reading the code) that it is okay to pass null as the argument to getListTrace. So Findbugs will warn you if you dereference object without checking for null.
That code doesn't look like it has a bug.
If you changed the code to check if object was null, what would you do? The most reasonable action would probably to throw a NullPointerException, right?
That's exactly what your code snippet does; it just lets java do the test automatically when accessing a method.
That this function doesn't check for a null pointer is not a bug. The bug would be if someone passed a null pointer into your function and wasn't prepared for it raising a NullPointerException.
Findbug cannot detect potential null pointer accesses. But Eclipse can give you a warning for potential null pointer access, if you activate the corresponding compiler warning in the preferences.
Raising bug report in such case would result in really big noise. You would get thousands of irrelevant bug messages in the perfectly correct code. Actually FindBugs does smarter thing. If it discovers that the method dereferences the argument without a null-check, it marks internally this method argument as #Nonnull. If you have an explicit annotation (like in TimK answer) which contradicts with this, you will get a warning. Otherwise FindBugs assumes that nobody uses this method with possibly-null argument. And when somebody actually does this, you will get a corresponding warning on the call site. Here's an example:
import java.util.Collections;
import java.util.List;
public class FBNull {
static class A {
String getArg() {
return "str";
}
}
public static List<String> getListTrace(A object) {
String arg = object.getArg();
return Collections.singletonList(arg);
}
public void callSite(A a) {
if (a == null) {
System.out.println("a is null");
}
System.out.println(getListTrace(a)); // NP_NULL_PARAM_DEREF
}
}
From the FindBugs poit of view getListTrace() method is ok. However the callSite method has a bug. It checks its argument for null explicitly, thus it can be null due to application logic. However, it's later passed to getListTrace() which immediately dereferences the argument. Thus you have a bug warning inside the getListTrace() method saying:
Bug: Null passed for non-null parameter of getListTrace(FBNull$A) in FBNull.callSite(FBNull$A)
This method call passes a null value for a non-null method parameter. Either the parameter is annotated as a parameter that should always be non-null, or analysis has shown that it will always be dereferenced.
So if you actually can pass nulls, it can be detected on the call sites.
Related
I have a question about Flutter and Null Safety.
For example I have this lines of code:
Future<dynamic> isLoggedIn() async {
Account account = Account(client);
Response? result = await account.get();
if (result == null) {
print(true);
}
}
I've marked result as nullable variable with Response?. So result can be null. Why Visual Studio gives me the warning The operand can't be null, so the condition is always false., if I check if result == null?
Do I misunderstand the concept of Null Safety? :-)
As also suggested by julemand101, the behavior of your ide is due to the fact that, when a variable is set using a method that returns a non-nullable type, the dart analyzer knows with certainty that the variable is not null (despite the type with which you declared the variable would allow null).
I too was surprised a little by the warning, because if you declare the variable by specifying its type, instead of using var, I would expect the dart analyzer to understand that the intent of the developer is to guard against possible changes. Then, thinking about it, I realized that if the method changed the signature and returned a nullable type, the compiler would force the developer to perform a null check, so in fact there is no reason to execute such a check until it is really needed.
However, you can make the warning disappear by using the comment // ignore: unnecessary_null_comparison or through the file analysis_options.yaml:
analyzer:
errors:
unnecessary_null_comparison: ignore
Edit:
the request can return null from server side.
If your account.get() method could return null, the ide would not report that warning to you. So I guess it's the signature of your method which is incorrect.
However, as for the question in the title ("the right way to tell Flutter that a variable can be null"), by declaring the variable as nullable you are leaving yourself the option of re-evaluating the variable with null or with a nullable type (and in that case then the null check would make sense).
Visual Studio gives you that warning because (I'm guessing because I did not see your get method) your get method is returning value that is not able to be a null value
Future<Response> get() async {
...
}
If you want it to be able to return null it should be declared like this
Future<Response?> get() async {
...
}
Using the Null Analysis of Eclipse:
It it possible to define other methods as initializing methods than Constructors?
I have a class like this:
public class Foo {
#NonNull
private Object fooObject;
public Foo() {
super();
}
public void onCreate() {
fooObject = //Something which is not available in the Constructor;
}
Here i get the warning that the NonNull field may has not been initialized. Is there any possibility to kind of declare the init-method as an initalizing one?
I could use #SuppressWarnings("null") for the constructor. But then I ignore all fields, which may instanciated somewhere.
Second chance i see is to make fooObject as #Nullable - but then i need check for null each time i use fooObject.
So is there any better solution?
Null-checking object initialization beyond the constructor is inherently difficult. Several sophisticated approaches exist, all of which require additional annotations.
In your example it seems to be near-impossible, to prove to the compiler, that onCreate() is always called before accessing the field.
A weaker solution has been proposed: #LazyNonNull, an annotation to be used on fields that are initially null, but once initialized can never go back to null. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=414237
Obviously, a static factory method, that gathers all necessary values before invoking a constructor (with arguments) would be a lot easier to get right.
I am writing an application which uses ORMLite to connect to a back-end database. Since the application will be run over VPN I am trying to minimize database calls.
In order to minimize database calls I have created a set of classes to wrap the values for each field. Each wrapper class stores the original value returned from the database and also a current value. This allows things like reverting to the original value, or checking whether the value is dirty (ie. only update the database if one or more fields are dirty).
The implication of this regarding ORMLite is that ORMLite never returns a null value when it queries the database (even if the database returns null). If there is a null value in the database it returns a fully initialized "wrapper" with the currentValue and originalValue variables set to null.
It seems that the right place to do this is in a custom persister such as (where StatefulIntegerProperty is the wrapper for the Integer):
public class StatefulIntegerPersister extends BaseDataType {
... misc. other code
#Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
Integer result = results.getInt(columnPos);
return new StatefulIntegerProperty((results.wasNull(columnPos)) ? null : result);
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) throws SQLException {
return sqlArg;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object obj) throws SQLException {
return ((StatefulIntegerProperty)obj).getCurrentValue();
}
#Override
public boolean isStreamType() {
return true; // this is a hack to work around ORMLite setting the value to null in the FieldType.resultToJava function
}
}
I have three questions:
Is this the correct approach?
In the ORMLite FieldType.resultToJava function it seems to do a null check and will replace my wrapper with null if the database returned null. Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach, and will I find later an unintended negative side effect?
What is the difference between the resultToSqlArg and sqlArgToJava methods in a custom persister, and specifically, which one of these should I use to wrap the value returned from the DB, and then what should I be doing in the other?
Is this the correct approach?
I don't understand why anything that you are doing here minimizes database calls. Can you start a discussion on the users' mailing list?
Right now you are overriding the resultToSqlArg(...) method when I think you want the sqlArgToJava(...). See below.
Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach...
Hrm. If it works then fine but it seems dangerous to use this setting in this manner. If I changed the behavior of the isStreamType() method then this may break your code. At the very least you should have unit tests to confirm this behavior that will break if you upgrade ORMLite.
That said, there is good handling in the code specifically around null values if isStreamType() is true.
What is the difference between the resultToSqlArg and sqlArgToJava...
I've fleshed out the javadocs for these.
resultToSqlArg takes the object from the SQL results and turns it into a java-object suitable to be an argument to SQL commands. For example, if you have a date-long type, this will extract a Long value from the database results.
sqlArgToJava takes the sql-arg value and converts it into our Java field. For example, if you have a date-long type, this will take a Long value and convert it into a Date which matches the entity field.
I think you should override the sqlArgToJava and not the resultToSqlArg.
After some debugging,I found "com.google.gwt.event.shared.UmbrellaException:One or
more exceptions caught, see full set in UmbrellaException#getCauses' when calling method: [nsIDOMEventListener::handleEvent]"(in web model) is caused by runtime null pointer.Question is why this kind of runtime null pointer exception didn't got thrown out under host model.Actually,blow code won't thrown out any exception and even got alert popup in my laptop(gwt 2.4+java 7 64bit+ubuntu 12.04 64bit+eclipse 3.7).Anybody knows how to enforce eclipse throw out exception whenever a runtime null on JavascriptObject pointer occurs.
public class GWTTest implements EntryPoint
{
public static class JsObj extends JavaScriptObject
{
protected JsObj()
{
}
public final native void setValue(String Value)/*-{
this.Value=Value;
alert(Value);
}-*/;
}
public void onModuleLoad()
{
JsObj jsObj = null;
jsObj.setValue("val");
}
}
The compiler performs a number of optimizations to transform GWT/Java into Javascript.
Types and methods are made final - this allows later steps to understand which methods need to be dispatched as normal, and which can be made static, just calling a single implementation.
Methods are made static, where possible, which allows methods to be inlined
Where possible and reasonable, methods are inlined
That said... When I compile your sample, the body of onModuleLoad() is optimized out to this:
null.nullMethod();
This is the GWT compiler's way of saying 'this will never work' - it notices that the value is always null, and so the method can't be invoked on it. But in Dev Mode, apparently the null object is left pointing at the window object in JavaScript. This is filed at http://code.google.com/p/google-web-toolkit/issues/detail?id=6625 in the GWT project.
If you need to make sure you don't act on a null, test for null before calling the method - it'll get optimized out if, in a test like yours, the value is always null. Runtime exceptions shouldn't be used for controlling code anyway, so you should never rely on a NullPointerException to do anything in your code.
I'm trying to integrate NHibernate.Validator with ASP.NET MVC client side validations, and the only problem I found is that I simply can't convert the non-interpolated message to a human-readable one. I thought this would be an easy task, but turned out to be the hardest part of the client-side validation. The main problem is that because it's not server-side, I actually only need the validation attributes that are being used, and I don't actually have an instance or anything else at hand.
Here are some excerpts from what I've been already trying:
// Get the the default Message Interpolator from the Engine
IMessageInterpolator interp = _engine.Interpolator;
if (interp == null)
{
// It is null?? Oh, try to create a new one
interp = new NHibernate.Validator.Interpolator.DefaultMessageInterpolator();
}
// We need an instance of the object that needs to be validated, se we have to create one
object instance = Activator.CreateInstance(Metadata.ContainerType);
// we enumerate all attributes of the property. For example we have found a PatternAttribute
var a = attr as PatternAttribute;
// it seems that the default message interpolator doesn't work, unless initialized
if (interp is NHibernate.Validator.Interpolator.DefaultMessageInterpolator)
{
(interp as NHibernate.Validator.Interpolator.DefaultMessageInterpolator).Initialize(a);
}
// but even after it is initialized the following will throw a NullReferenceException, although all of the parameters are specified, and they are not null (except for the properties of the instance, which are all null, but this can't be changed)
var message = interp.Interpolate(new InterpolationInfo(Metadata.ContainerType, instance, PropertyName, a, interp, a.Message));
I know that the above is a fairly complex code for a seemingly simple question, but I'm still stuck without solution. Is there any way to get the interpolated string out of NHValidator?
Ok, so I know this is an old question, but I stumbled across this when trying to do the same thing, and it helped me get started - so I thought I would provide an answer.
I think the code in the question was on the right track but there are a couple of problems. The interpolator was not completely initialised with the ResourceManager and Culture details, and it doesn't seem to allow for the fact that you can only have one DefaultMessageInterpolator per validation attribute. Also, you don't need an instance of the object you are validating to get an interpolated message.
In the code in the question, where you are initialising the interpolator with the attribute value, you also need to initialise the interpolator with details of the ResourceManager to be used.
This can be done using the overloaded Initialize method on DefaultMessageInterpolator which has the following signature:
public void Initialize(ResourceManager messageBundle,
ResourceManager defaultMessageBundle,
CultureInfo culture)
The first parameter is a user-defined ResourceManager in case you want to use your own resource file for error messages, you can pass a null if you just want to use the default ResouceManager, the second parameter is the default ResourceManager - you can pass
new ResourceManager(
NHibernate.Validator.Cfg.Environment.BaseNameOfMessageResource,
Assembly.GetExecutingAssembly());
for this, the last parameter is the culture to use, (NHibernate.Validator comes with resource files with validation messages in several languages) - if you pass a null in to this it will just use CultureInfo.CurrentCulture
Lastly, you can only have one DefaultMessageInterpolator per attribute, so you will need to create a new DefaultMessageInterpolator for each validation attribute. You could make use of the DefaultMessageInterpolatorAggregator to handle this, or just roll your own.
I hope this helps someone.
Thanks for your help all--I'd upvote if I could. I just wanted to add that in addition to the first Initialize call on the DefaultMessageInterpolator that Stank illustrates, I also had to make a second different Initialize call to fully initialize it (I was getting some Null Reference Exceptions using only the first call). My code is as follows:
string interpolatedMessage = "";
DefaultMessageInterpolator interpolator = new DefaultMessageInterpolator();
interpolator.Initialize(null,
new ResourceManager(
NHibernate.Validator.Cfg.Environment.BaseNameOfMessageResource,
Assembly.Load("NHibernate.Validator")),
CultureInfo.CurrentCulture);
interpolator.Initialize(attribute as Attribute);
if (attribute is IValidator && attribute is IRuleArgs)
{
IValidator validator = attribute as IValidator;
IRuleArgs ruleArgs = attribute as IRuleArgs;
InterpolationInfo interpolationInfo = new InterpolationInfo(
validatableType,
null,
propertyName,
validator,
interpolator,
ruleArgs.Message);
interpolatedMessage = interpolator.Interpolate(interpolationInfo);
}