Lambda Procedure error: java.lang.NullPointerException

Alright, so I’m stumped here. I followed the tutorial on reusable functions, and even with the simplest of code in the procedure, I still get a java error:

2018-04-09 22:42:38.341 [ERROR] [eclipse.smarthome.model.script.rules] - dimmers.rules - Exception in 'All Lights Change' rule java.lang.NullPointerException

Below is the entirety of my rules file (originally it was more complex, but I’ve stripped it completely down to try to isolate what’s triggering the error):

import org.eclipse.xtext.xbase.lib.Procedures

val logName = "rules"
val fileName = "dimmers.rules"

val Procedures$Procedure3<GenericItem, String, String> storeItemState = [ currentItem, previousState, newState |
    logInfo(logName, "testing function")
]

rule "All Lights Change"
	when
		Item Light_Den changed or
        Item Light_Kitchen_Pendant changed or
        Item Light_FamilyRoom changed or
        Item Light_Office changed or
        Item Light_MasterBedroom changed or
        Item Light_NicksRoom changed
	then
		try {
			Thread::sleep(100) // give persistence time to catch up
            val genItem = triggeringItem as GenericItem
            storeItemState.apply(genItem, previousState.toString, triggeringItem.state.toString)
        } catch (Throwable e) {
			logError(logName, "{} - Exception in 'All Lights Change' rule {}", fileName, e.toString)
		}
	end

If anybody has any suggestions for me to try, I’m all ears. I’m not sure what I’m doing wrong here.

For reference, I’m on the 2.2 docker image, and I’m writing my rules in VSCode.

Thanks in advance!

Put the try/catch into the lambda for a start.

But I don’t think the error is coming from the lambda.

You don’t need the Thread::sleep since you are not using persistence in this rule.

Add some logging to verify that it is on the lambda that the error is thrown.

Thanks for the reply.

I actually had a try/catch in the lambda as well, to no avail (same error). Right now the only thing in the lambda is a log entry, and that doesn’t fire.

However, I also tried logging the arguments I’m passing to the lambda prior to calling the procedure, and it displays values just fine. I even tried changing the procedure to a function.

The error in every case I’ve tried is always from the rule’s catch, not the lambda.

Edit: the thread sleep is left over from my original content before I stripped it all out to figure what’s going on.

Where do you define that?

@opus previousState is an implicit variable in the “changed” event.

:blush: ups, Sorry, I never used that before.

@opus no worries. Thanks for trying.

I’ve added a try/catch back to the lambda just for the heck of it. I’ve also further simplified the rule and added additional logging before, during, and after the lambda call. The rules file (in its entirety now looks like the following:

import org.eclipse.xtext.xbase.lib.Procedures

val logName = "rules"
val fileName = "dimmers.rules"

val Procedures$Procedure1<String> storeItemStateTest = [ s |
    try {
        logInfo(logName, "Log test lambda called.")
    } catch(Throwable e) {
        logError(logName, "Error in lambda - {}", e.toString)
    }
]

rule "All Lights Change"
	when
		Item Light_Den changed or
        Item Light_Kitchen_Pendant changed or
        Item Light_FamilyRoom changed or
        Item Light_Office changed or
        Item Light_MasterBedroom changed or
        Item Light_NicksRoom changed
	then
		try {
            val genItem = triggeringItem as GenericItem
            logInfo(logName, "Log test before calling lambda")
            storeItemStateTest.apply(genItem.name)
            logInfo(logName, "Log test after calling lambda")
        } catch (Throwable e) {
			logError(logName, "{} - Exception in 'All Lights Change' rule {}", fileName, e.toString)
		}
	end

This results in the log entry before the lambda call being fired, followed by the same NullPointerException:

2018-04-10 07:45:55.947 [INFO ] [eclipse.smarthome.model.script.rules] - Log test before calling lambda
2018-04-10 07:45:55.948 [ERROR] [eclipse.smarthome.model.script.rules] - dimmers.rules - Exception in 'All Lights Change' rule java.lang.NullPointerException

I feel like I can’t simplify the lambda and rule anymore than this. It’s bizarre to me why this isn’t working. In the interest of full disclosure, VSCode does complain about a missing “End” tag, but it’s obviously there, and I’m pretty confident there are no syntax errors otherwise (including white spaces as I recreated everything in nano). Also, I was getting that missing “End” tag error before I added the lambda, where the rule works fine. So, I think it’s safe to say the problem is with the lambda procedure, but can’t understand why.

One very important statement I made above is I don’t think the error is coming from the lambda.

You usually get a different error and stack trace when an error is generated inside a lambda verses from inside a Rule.

That exception usually occurs when the Rules DSL tries to convert something to another type (e.g. a Number to a String) and fails to do so. So I would guess that the error is occuring on the genItem.name for some reason. I’m not saying it makes sense nor do I have a solution, but I think the focus on the body if the lambda is misplaced. I don’t think the error is coming from there.

That implies there is some other syntax error somewhere. Perhaps a missing } or ]. Do you see the same error/warning in openhab.log?

@rlkoshak I agree that it’s not the lambda itself, versus the calling of the lambda from the rule. I also thought the same thing as you regarding the item name, so I’ve tried by passing a string literal into it, netting the same error.

The behavior to me suggests that it can’t find the lambda procedure to call it, yet for whatever reason the editor seems to be fine with everything.

I’ve also completely cleared the file out and written the simplest “rule, when, then, end” possible, and I still see the syntax error on the “end”. If I close and reopen the file, the error disappears, so I think there’s some order of operations where the parser gets confused. For that reason, I’m pretty sure that piece, at least, is a red herring.

You are probably right, but make sure you are not seeing any warnings or errors in openhab.log when the file changes.

That could be. I really don’t see anything obvious. When you comment out the call to the lambda the error for sure goes away?

When I hit a brick wall I step back and see if there is some other way I can proceed to avoid the error. So what are you trying to accomplish in this Procedure? Do you need a Procedure to do this? Can you take advantage of triggeringItem and the like to combine the Rules that would call this Procedure into one? From the name it sounds like you want to save the state of a bunch of Items and later restore the states, correct? If that is the case have you considered using the storeStates and restoreStates Actions? Do you have other lambdas that are working?

At this point, the only thing that stands out is the inconsistent indentation which should be meaningless.

the lambda is itself an Object. What happens when you try to log it?

logInfo(logName, storeItemStateTest)

of

logInfo(logName, storeItemStateTest.toString)

@rlkoshak. That’s neat about the object bit. It doesn’t like your first log offering, but casting to string completes the rule execution:

2018-04-10 12:27:45.644 [INFO ] [eclipse.smarthome.model.script.rules] - Log test before calling lambda
2018-04-10 12:27:45.645 [INFO ] [eclipse.smarthome.model.script.rules] - Proxy for org.eclipse.xtext.xbase.lib.Functions$Function1: [param s | {
  org.eclipse.xtext.xbase.impl.XTryCatchFinallyExpressionImpl@37a3ed63
} ]
2018-04-10 12:27:45.645 [INFO ] [eclipse.smarthome.model.script.rules] - Log test after calling lambda

So, it appears that it sees the lambda, at least.

To answer your design questions… originally I was doing all the work in the rule, and it worked fine. I moved it to a function/procedure to be reused by another rule I’m planning to write for the scenes supported by the dimmer items. So, it was a matter of refactoring to not repeat myself. Ironically I assumed putting the functionality in a lambda would be the easy part. The intent is to take the affected item, and apply some logic to update accessory items (namely a LastUpdated and a PreviousValue item). I’m doing this because I want to be able to access that PreviousValue item to restore that value on a certain scene (eg: double tap up or something, I haven’t decided). So, with that goal in mind, I don’t believe that storeStates would work for me.

Overall, I’m just at a loss for why I can’t seem to call a lambda from a rule, no matter how stripped down I make the code.

I probably wouldn’t implement this with a lambda anyway. I’d create one Rule triggered by all the Items you want this to operate with (on OH 2.3 triggered by a Member of GroupName trigger instead) and apply Design Pattern: Associated Items to access the LastUpdated and PreviousValue. Then put the parts that are different in their own Rules. This would be an application of Design Pattern: Separation of Behaviors.

Depending on what else you need to do that is different between the two, you could even merge those rules if there isn’t that much and use if(triggerintItem instanceof DimmerItem) to determine what you are dealing with. Obviously, there is a balance between a long Rule that does everything and short Rules that are easier to read but sometimes, IMHO, it just isn’t worth the effort to solve some problems like this that make no sense.

I’m truly stumped on the lambda but I’ve long since eliminated all the lambdas from my setup so don’t have recent experience with them. But I’ve not seen anywhere reported similar issues on the forum.

The warnings in VSCode still give me pause though. When there is more than one weird thing going on they are usually related. I’ve pasted your Rule in from above with the Procedure and my VSCode does not identify any errors at all. That in-and-of-itself is suspicious and points to perhaps a more significant problem with your setup or environment. I’ll admit it seems unlikely but when the weirdness piles up the problem is often a failing SD card.

@rlkoshak thanks so much for the help.

I’m inclined to agree with you. I was hoping to have a smaller functions that do one task so it’s nicely separated. That all being said, I was only using lambdas because a reusable function seemed appealing. I’ll admit it’s not that much of a time-saver or the end of the world to include the logic in the rule.

The “associated items” design pattern is exactly what I had going on in the lambda originally, and I am aware of that “member of” logic on the way with 2.3. There’s no SD card in my setup (it’s running in a container on a server), so I think, as you said, it’s probably just not worth the trade-off of figuring out what edge case this may or may not be. The VSCode warning is gone if I wipe the file and paste it all back in. Later, after who-knows-what-edit, it returns.

Oh well. It’s a bummer, but there is more than one way to frost a cake. Thanks again for taking a shot at it.

You might run a chdisk just to make sure you are not hitting a bad sector or something.

Hi Paul,

In your lambda Procedure, you use a global variable (logName). The lambda has no access to global variables. So the first argument of logInfo is null.
I think it is the issue.
Try with :

logInfo("DEBUG", "testing function")

@renstat wow, that was it. Now that you say that, it makes perfect sense.

Thank you so much. Ironic that in an effort to strip everything down to narrow down the issue, I left (what I thought was the simplest thing) a log entry, and THAT was the issue.

Thanks again!

Doh! I can’t believe I missed that. Good eye Alain!