-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: update necessary if shadow cleared #196
Changes from 1 commit
f21c308
7d8127e
4a68d48
95a6664
fc56817
cee44f5
fc7890b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
import com.aws.greengrass.util.SerializerFactory; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | ||
import com.fasterxml.jackson.databind.node.LongNode; | ||
import com.fasterxml.jackson.databind.node.ObjectNode; | ||
import lombok.Getter; | ||
|
@@ -28,6 +29,7 @@ | |
* Class for managing operations on the Shadow Document. | ||
*/ | ||
@Getter | ||
@JsonDeserialize(using = ShadowDocumentDeserializer.class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using a custom deserializer and new There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The document isn't null though right, just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah just the state There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did a code search and it's less cases of this than what i thought, will refactor |
||
public class ShadowDocument { | ||
@JsonProperty(value = SHADOW_DOCUMENT_STATE, required = true) | ||
private ShadowState state; | ||
MikeDombo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package com.aws.greengrass.shadowmanager.model; | ||
|
||
import com.aws.greengrass.util.SerializerFactory; | ||
import com.fasterxml.jackson.core.JsonParser; | ||
import com.fasterxml.jackson.databind.DeserializationContext; | ||
import com.fasterxml.jackson.databind.JsonDeserializer; | ||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | ||
|
||
import java.io.IOException; | ||
|
||
public class ShadowDocumentDeserializer extends JsonDeserializer<ShadowDocument> { | ||
// hack to prevent StackOverflowException for custom deserialize, | ||
// allows us to use jackson's default deserialization for type within | ||
// a custom deserializer | ||
static { | ||
SerializerFactory.getFailSafeJsonObjectMapper().addMixIn(ShadowDocument.class, DefaultJsonDeserializer.class); | ||
} | ||
|
||
@JsonDeserialize | ||
private interface DefaultJsonDeserializer { | ||
// Reset default json deserializer | ||
} | ||
|
||
@Override | ||
public ShadowDocument deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
|
||
ShadowDocument document = ctxt.readValue(p, ShadowDocument.class); | ||
if (document.getState() == null) { // handle {"state": null} document | ||
ShadowDocument clearDocument = new ShadowDocument(document); | ||
clearDocument.getState().setClear(true); | ||
return clearDocument; | ||
} | ||
return document; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,12 @@ | |
|
||
import com.aws.greengrass.shadowmanager.util.JsonMerger; | ||
import com.aws.greengrass.shadowmanager.util.JsonUtil; | ||
import com.fasterxml.jackson.annotation.JsonIgnore; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.node.ObjectNode; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
import java.util.Iterator; | ||
|
||
|
@@ -33,6 +35,13 @@ public class ShadowState { | |
@JsonProperty(SHADOW_DOCUMENT_STATE_REPORTED) | ||
private JsonNode reported; | ||
|
||
/** | ||
* If true, this {@link ShadowState} represents the {"state": null} document, which resets shadow state. | ||
*/ | ||
@Setter | ||
@JsonIgnore | ||
private boolean clear; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why? We cannot handle nulls without this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can, although we use shadowDocument.state a bunch of places in the code. thinking was that this would be better than adding null checks everywhere There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know what it would look like of course, but I think that marking state as |
||
|
||
public ShadowState() { | ||
this(null, null); | ||
} | ||
|
@@ -42,6 +51,11 @@ public ShadowState(final JsonNode desired, final JsonNode reported) { | |
this.reported = nullIfEmpty(reported); | ||
} | ||
|
||
private ShadowState(final JsonNode desired, final JsonNode reported, boolean clear) { | ||
this(desired, reported); | ||
this.clear = clear; | ||
} | ||
|
||
/** | ||
* Creates a new instance of the shadow state by deep copying the desired and reported nodes. | ||
* | ||
|
@@ -50,7 +64,8 @@ public ShadowState(final JsonNode desired, final JsonNode reported) { | |
public ShadowState deepCopy() { | ||
return new ShadowState( | ||
isNullOrMissing(this.desired) ? this.desired : this.desired.deepCopy(), | ||
isNullOrMissing(this.reported) ? this.reported : this.reported.deepCopy()); | ||
isNullOrMissing(this.reported) ? this.reported : this.reported.deepCopy(), | ||
this.clear); | ||
} | ||
|
||
/** | ||
|
@@ -103,6 +118,9 @@ public void update(JsonNode updatedStateNode) { | |
* @return a JSON node containing the shadow state. | ||
*/ | ||
public JsonNode toJson() { | ||
if (clear) { | ||
return JsonUtil.OBJECT_MAPPER.nullNode(); | ||
} | ||
final ObjectNode result = JsonUtil.OBJECT_MAPPER.createObjectNode(); | ||
if (this.desired != null) { | ||
result.set(SHADOW_DOCUMENT_STATE_DESIRED, this.desired); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems to think that returning null is bad... so do we think this is a problem for our customers? Does the cloud shadow service ever return null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my initial understanding was wrong, cloud shadow service does return null for update accepted topic. verified using the IoT mqtt test client and a real shadow