Does the MVEL Null-Safe operator work on methods? - mvel

I have a question regarding the MVEL null-safe (?) operator.
Say I have the following Java class:
public class Traveler {
private Set<String> visitedCountries;
public Set<String> getVisitedCountries() {
return visitedCountries;
}
}
If I have an MVEL expression like this:
traveler.visitedCountries.contains("France")
I get a NullPointerException if the visitedCountries field is null. To get around this, I can use the null-safe operator:
traveler.?visitedCountries.contains("France")
If visitedCountries is null, this expression evaluates to null instead of throwing the NPE.
My question is this: does the null-safe operator work on method invocations? For example:
traveler.getVisitedCountries().contains("France")
will throw a NullPointerException if getVisitedCountries() returns null.
But what happens if I put in the null-safe operator? What will the following do if the field visitedCountries is null?
traveler.?getVisitedCountries().contains("France")

As it turns out, the expression
traveler.?getVisitedCountries().contains("France")
does observe the null-safe operator. It would evaluate to null here. Unit test:
#Test
public void testMVELNullSafeOnMethod() throws Exception {
Traveler traveler = new Traveler();
// traveler visitedCountries field is null
String expression = "traveler.?getVisitedCountries().contains(\"France\")";
Serializable exp = MVEL.compileExpression(expression);
Map<String, Object> map = new HashMap<String, Object>();
map.put("traveler", traveler);
Boolean response = (Boolean) MVEL.executeExpression(exp, map);
assertNull(response);
}

Related

Non nullable field of object created via reflection is null

I have next class structure:
class ExampleResponse(
#SerializedName("status")
val status: String
)
I am creating instance of this class via reflection:
fun convert(typeAdapterFactory: TypeAdapterFactory, gson: Gson): Optional<*> {
return try {
val genericTypeClassName = "com.example.package.ExampleResponse"
val genericClass = Class.forName(genericTypeClassName)
val genericTypeAdapter = gson.getDelegateAdapter(typeAdapterFactory, TypeToken.get(genericClass))
val response = genericTypeAdapter.fromJson("{}")
Optional.of(response)
} catch (e: Exception) {
Optional.empty<Any>()
}
}
I am waiting that on the line genericTypeAdapter.fromJson("{}") it will throw exception, because status will be null. But I am receiving instance of ExampleResponse with null status field.
I want to return Optional.empty() if status is null. How can I achieve this without checking fields? (checking field to non null is not acceptable because the real function is universal and I won't know what class I'll receive here).
Gson doesn't know when a field can/cannot be null, since it's a Java library and Java knows nothing about nullability.
This question and answers suggests some workarounds:
Gson optional and required fields

Null Safety on IF comparison in Kotlin

I have a question about how Kotlin manages NULL safety on comparison.
I have this code:
imageFile.addListener { _ , oldValue : File?, newValue : File? ->
run{
if(oldValue?.absolutePath != newValue?.absolutePath) loadFile()
}
}
It works fine, however if I change it to
imageFile.addListener { _ , oldValue : File?, newValue : File? ->
run{
if(oldValue!!.absolutePath != newValue?.absolutePath) loadFile()
}
}
It throws a NullPointerException and that's obvious, because when the application starts oldValue is NULL.
How Kotlin manages this comparison the first time?
Thanks for your help.
You are using safe call which avoid NullPointerException:
option is the safe call operator, written ?.
returns null if any of the properties in it is null.
Second option not-null assertion operator throws exception
The !! Operator
the not-null assertion operator (!!) converts any value to a non-null type and throws an exception if the value is null

Nullable type still throw nullpointer exception at Kotlin

This code below throw nullpointer exception in third line. Because objectHashMap is null. But how is that possible. Its a nullable type and it can be null.
val objectsGTypeInd = object : GenericTypeIndicator<HashMap<String, Post>>() {}
val objectHashMap: HashMap<String, Post>? = dataSnapshot?.getValue(objectsGTypeInd)
val postList = ArrayList<Post>(objectHashMap?.values)
"collection == null" message writing at logcat
When you call ArrayList<Post>(null), you'll get this problem. If your objectHashMap is null, or it contains no values, you'll have a null there. The compiler isn't really complaining about you having a null, it's complaining about the fact that you're passing it to the ArrayList() constructor.
If you look at the JavaDoc for ArrayList, it states that the collection can't be null, or you'll get a NullPointerException:
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* #param c the collection whose elements are to be placed into this list
* #throws NullPointerException if the specified collection is null
*/
The problem is that objectHashMap?.values evaluates to null when:
objectHashMap itself is null or
values property is null
You’re using the safe operator ?. and this can obviously lead to null results which you shouldn’t pass to an ArrayList. You could provide a default value using the Elvis operator:
ArrayList<Post>(objectHashMap?.values ?: defaultValues)
Alternatively, an empty list can be created like this:
if(objectHashMap==null) ArrayList<Post>() else ArrayList<Post>(objectHashMap.values)
Note that in the second part, the compiler lets you use objectHashMap as a non-nullable type since you checked it in the if.
Kotlin docs state:
b?.length
This returns b.length if b is not null, and null otherwise.
Thus, you might be calling ArrayList<Post>(null) since objectHashMap: HashMap<String, Post>? is of type nullable due to the question mark at the end ?.
From the Kotlin docs about ArrayList, which link us to Java Class ArrayList<E> and the constructor you're using:
public ArrayList(Collection<? extends E> c) states:
Throws:
NullPointerException - if the specified collection is null

Kotlin Spring Jdbc Cannot Use NULL

I have the following method in a Spring Boot application using Kotlin. It won't compile because addValue method takes String paramName, and Object value. In my case passing NULL is a valid case, because I want all bankers, not ones from a specific branch.
Is there anyway to work around this in Kotlin.
override fun getBankers(branchId: UUID?): Iterable<Banker> {
val query = this.sql.getProperty("banker.selectByBranch")
val params = MapSqlParameterSource()
.addValue("branchId", null)
return this.jdbcTemplate.query(query, params, BankerRowMapper())
}
If I do branchId!! I get an NPE.
If you call your method with a null branchId parameter and inside your method you use that parameter with the !! operator, you will get a NullPointerException because that's what the !! operator does. Shouldn't you use the parameter in your method somehow? Maybe like this:
override fun getBankers(branchId: UUID?): Iterable<Banker> {
val query = this.sql.getProperty("banker.selectByBranch")
val params = MapSqlParameterSource()
.addValue("branchId", branchId?.toString())
return this.jdbcTemplate.query(query, params, BankerRowMapper())
}

XTend null safe throws NullPointerException

I am porting my template code to XTend. At some point I have this type of condition handling in a test case:
#Test
def xtendIfTest() {
val obj = new FD
if (true && obj?.property?.isNotNull) {
return
}
fail("Not passed")
}
def boolean isNotNull(Object o) {
return o != null
}
class FD {
#Accessors
String property
}
This works as expected as the property is null and the test will fail with "Not passed" message. But a simple change in the return type of isNotNull method to Boolean (wrapper):
def Boolean isNotNull(Object o) {
return o != null
}
fails with a NullPointerException. Examining the generated java code for this I can see that XTend is using an intermediate Boolean object expression and that is the cause of NPE. Am I missing the point of the XTend null safe operator (?.) or I can't use a method like this after the operator?
Thanks.
The operator behaves properly. The exception is thrown because of the usage of a Boolean in an if-expression, which requires auto-unboxing.
If you try the following:
#Test
def xtendIfTest() {
val Boolean obj = null
if (obj) {
return
}
fail("Not passed")
}
You will also run into a NullPointerException.
This is consistent with the Java Language Specification (https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.8) - when auto-unboxing is required this can yield a NullPointerException:
#Test
public void test() {
Boolean value = null;
if (value) { // warning: Null pointer access: This expression of type Boolean is null but requires auto-unboxing
// dead code
}
}
Hope that helps.
Short answer: Change the second null-safe call to a regular call.
I.e. change
obj?.property?.isNotNull
to this:
obj?.property.isNotNull
Long answer:
The docs describe the null-safe operator thusly:
In many situations it is ok for an expression to return null if a
receiver was null
That means the second call in your example, property?. won't even call isNotNull if the left side of the call was null. Instead, it will return null. So the conditional "effectively" evaluates to:
if (true && null) { // causes NPE when java tries to unbox the Boolean
(By the way - the true is superfluous in this context, but I'm keeping it just in case you had another condition to check - I'm assuming you're just simplifying it to true for this example.)
If you make the change I'm suggesting, obj?.property will be evaluated, then the result will be passed to isNotNull, evaluating to this:
if (true && isNotNull(null)) {
which returns the proper Boolean object that will be auto-unboxed as expected.
A Word of Caution
In your first form of isNotNull, i.e. the one returning primitive boolean, you should actually get a warning like "Null-safe call of primitive-valued feature isNotNull, default value false will be used".
This is because you're stretching the intent of the null-safe call, which is to return null without invoking the right side method if the left side of the operator was null. But if your isNotNull returns a primitive boolean, the whole expression obviously can't evaluate to null, so Xtend uses a default instead, which is false for booleans.
To emphasize the problem in a different way - it evaluates to false without calling isNotNull - that means even if you used a method isNull after the operator, it would still return false!
The docs also mention this behavior (albeit in general terms):
For primitive types the default value is returned (e.g. 0 for int).
This may not be what you want in some cases, so a warning will be
raised by default
So I recommend always using a non-primitive return value on the right-hand side of a null-safe call. But if you're going to convert the isNotNull to a regular call as I suggested, this rule doesn't apply, and either return type is fine.