Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

null is not an accepted type so convert it to an accepted type #3521

Merged
merged 1 commit into from
May 27, 2017
Merged

null is not an accepted type so convert it to an accepted type #3521

merged 1 commit into from
May 27, 2017

Conversation

martinvw
Copy link
Contributor

null is not an accepted type so convert it to an accepted type

Overcomes NPE's in a places where the state is broadcasted to

Fixes #3520

Copy link
Contributor Author

@martinvw martinvw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some context

if (item != null && !isAccepted(item, state)) {
for (Class<? extends State> acceptedType : item.getAcceptedDataTypes()) {
State convertedState = state.as(acceptedType);
if (convertedState != null) {
LoggerFactory.getLogger(ItemUtil.class).debug("Converting {} '{}' to {} '{}' for item '{}'",
state.getClass().getSimpleName(), state.toString(),
convertedState.getClass().getSimpleName(), convertedState.toString(), item.getName());
state.getClass().getSimpleName(), state, convertedState.getClass().getSimpleName(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not call toString on logging arguments, just pass them on as an object they will be converted by logging framework if the log level applies

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if (state == null) {
return UnDefType.NULL;
}

if (item != null && !isAccepted(item, state)) {
for (Class<? extends State> acceptedType : item.getAcceptedDataTypes()) {
State convertedState = state.as(acceptedType);
if (convertedState != null) {
LoggerFactory.getLogger(ItemUtil.class).debug("Converting {} '{}' to {} '{}' for item '{}'",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho this is a real strange solution to overcome a static logger. Now you are going to re-fetch the logger from the factory each time you pass by this debug (!!!) statement which is really often for this specific line. The coding guidelines leave room to have static loggers if required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kaikreuzer what is your view on this specific solution

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static logger would definitely be ok for me here

@@ -75,14 +75,18 @@ public static void assertValidItemName(String itemName) throws IllegalArgumentEx
}
}

public static State convertToAcceptedState(final State state, final Item item) {
public static State convertToAcceptedState(State state, Item item) {
if (state == null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the core of the actual change :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how null actually gets in here. IMHO we should fix the root cause of it first. Still, it's valid to make it fail-safe here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@martinvw I think we should not silently swallow this situation, but log an error (incl. stacktrace) nonetheless to highlight that there is some bug somewhere in the code as we should never get here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a log statement

if (itemName != null && !itemName.isEmpty()) {
return itemName.matches("[a-zA-Z0-9_]*");
}
return StringUtils.isNotEmpty(itemName) && itemName.matches("[a-zA-Z0-9_]*");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry could not leave it like that :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, do we think that itemName of 0 characters is valid....?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 and no, AFAIK it needs to be a least one character long

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and no, AFAIK it needs to be a least one character long

@kaikreuzer agree? Should it be a separate PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certainly agree. Yes, to be clean, you can do it in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just see that we just did a isNotEmpty check so only the regex looked misleading but nothing will change :-D

@martinvw
Copy link
Contributor Author

@kaikreuzer imho this should solve the problem which was mentioned in the issue #3520 how were you able to reproduce it?

And on the community forum: https://community.openhab.org/t/java-lang-nullpointerexception-every-few-seconds/28944

@sjsf
Copy link
Contributor

sjsf commented May 26, 2017

The main question remains: What is the root-cause? Items should initially have a UnDefType.NULL state, so something recently must have changed which breaks with this assumption. Any clues?

@sjsf
Copy link
Contributor

sjsf commented May 26, 2017

GroupItems without a function maybe? Then it could have been #3411

@kaikreuzer
Copy link
Contributor

I think this is a likely a correct assumption...

@martinvw
Copy link
Contributor Author

martinvw commented May 26, 2017

If I follow up the call-stack, I arrive here:
ItemUtil.convertToAcceptedState
called from
ThingManager line 128 thingHandlerCallback.stateUpdated
called from
BaseThingHandler.updateState

Why can't it be a binding which just call's:

updateState(channelUID, null);

The main question remains: What is the root-cause? Items should initially have a UnDefType.NULL state, so something recently must have changed which breaks with this assumption. Any clues?

Items do initially have the state UnDefType.NULL but if we accept the state null, at one moment in time the oldState will become null as well, or did I misunderstand you?

@sjsf
Copy link
Contributor

sjsf commented May 26, 2017

Why can't it be a binding which just call's:
updateState(channelUID, null);

Because then (as bad as it is...) it would have failed with an NPE in
ItemUtil line 94, if I'm not mistaken.

@martinvw
Copy link
Contributor Author

Well spotted, yes I agree on that, so my change most likely doesn't fix the issue

@martinvw
Copy link
Contributor Author

I have my sister visiting, but I'll add changes later to fix setting of the state of e group.

if (itemName != null && !itemName.isEmpty()) {
return itemName.matches("[a-zA-Z0-9_]*");
}
return StringUtils.isNotEmpty(itemName) && itemName.matches("[a-zA-Z0-9_]*");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey, you missed to remove this empty line :-)

@martinvw
Copy link
Contributor Author

I don't see it coming from the mentioned PR either (no call to setState which might contain null), what do you think about this one:
GroupItem.java#L329

@martinvw
Copy link
Contributor Author

martinvw commented May 26, 2017

I don't see it coming from the mentioned PR either (no call to setState which might contain null), what do you think about this one: GroupItem.java#L329

Then I'm most likely missing something because my branch contains no function which can return null either. Can you point out the line where you think its actually assigning null to the oldState?

Maybe equality can, but then all items must have state null :-S

@martinvw
Copy link
Contributor Author

martinvw commented May 26, 2017

Another likely suspect, #3438

https://github.com/eclipse/smarthome/blob/master/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/types/State.java#L29

IMHO we should also add logging for this case, because it means there is a conversion requested which is not possible. For example requesting conversion of an OpenClosedType to a HSBType.

@martinvw
Copy link
Contributor Author

@triller-telekom can you take a look at NPE in combination with the change and line to which I referred, do you think this might be the cause of this? Thanks!

@kaikreuzer
Copy link
Contributor

You are right, the issue is definitely in 6939315#diff-543ecd419447346e6a177db8638e3ad0R74 - the as() method is allowed to return null and if you feed in an UNDEF at that place, the state will (now) be set to null internally. This worked in the past as UNDEF wasn't a Convertable state and thus was set directly.

@martinvw
Copy link
Contributor Author

So do you mean an UNDEF is converted to null, should we change the default implementation in that case?

Or should UnDefType override that method with return this;

Fixes #3520

Signed-off-by: Martin van Wingerden <martinvw@mtin.nl>
@kaikreuzer
Copy link
Contributor

Not sure how we best get back the behavior we had with the "Convertibles" - I'd leave it to @SJKA & @triller-telekom to decide as they both worked on that.

Copy link
Contributor

@kaikreuzer kaikreuzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks - so let's merge this as a first fix, but have @triller-telekom come up with a follow-up PR that fixes the underlying issue.

@kaikreuzer kaikreuzer merged commit cd69eba into eclipse-archived:master May 27, 2017
@martinvw martinvw deleted the feature/3520-convert-null-before-broadcasting-it branch May 28, 2017 07:14
@kaikreuzer kaikreuzer modified the milestone: 0.9.0 Jun 26, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants