Skip to content

Commit

Permalink
server-demo: change REST API, use string instead of Number for Integer
Browse files Browse the repository at this point in the history
This is because Javascript number does not support safely number larger
than Number.MAX_SAFE_INTEGER (2^53 - 1) without usage of BigInt... LWM2M
need to handle bigger number than that (until 64 bit signed integer)
  • Loading branch information
sbernard31 committed Nov 16, 2021
1 parent d5bb0da commit ea3c84a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,20 @@ private Object deserializeValue(JsonNode val, ResourceModel.Type type) {
}
break;
case INTEGER:
if (val.canConvertToLong() && val.canConvertToExactIntegral()) {
// we use String for INTEGER because
// Javascript number does not support safely number larger than Number.MAX_SAFE_INTEGER (2^53 - 1)
// without usage of BigInt...
if (val.isTextual()) {
try {
return Long.parseLong(val.asText());
} catch (NumberFormatException e) {
throw new IllegalArgumentException(String.format("%s is not a valid Long.", val), e);
}
} else if (val.canConvertToLong() && val.canConvertToExactIntegral()) {
// we also tolerate number but this is not advised
return val.asLong();
} else {
raiseUnexpectedType(val, type, "number(long)", val.getNodeType());
raiseUnexpectedType(val, type, "string", val.getNodeType(), "(number is tolerated but not advised)");
}
break;
case FLOAT:
Expand Down Expand Up @@ -204,8 +214,13 @@ private Object deserializeValue(JsonNode val, ResourceModel.Type type) {

private void raiseUnexpectedType(JsonNode value, ResourceModel.Type modelType, String expectedType,
JsonNodeType currentType) {
throw new IllegalArgumentException(
String.format("Unexpected JSON type of 'value' field [%s]: a JSON %s is expected for %s but was %s",
value.toString(), expectedType, modelType, currentType.toString().toLowerCase()));
raiseUnexpectedType(value, modelType, expectedType, currentType, null);
}

private void raiseUnexpectedType(JsonNode value, ResourceModel.Type modelType, String expectedType,
JsonNodeType currentType, String postDescription) {
throw new IllegalArgumentException(String.format(
"Unexpected JSON type of 'value' field [%s]: a JSON %s is expected for %s but was %s. %s",
value.toString(), expectedType, modelType, currentType.toString().toLowerCase(), postDescription));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
Expand Down Expand Up @@ -61,36 +62,38 @@ public void serialize(LwM2mNode src, JsonGenerator gen, SerializerProvider provi
if (rsc.isMultiInstances()) {
Map<String, Object> values = new HashMap<>();
for (Entry<Integer, LwM2mResourceInstance> entry : rsc.getInstances().entrySet()) {
if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
values.put(entry.getKey().toString(),
new String(Hex.encodeHex((byte[]) entry.getValue().getValue())));
} else {
values.put(entry.getKey().toString(), entry.getValue().getValue());
}
values.put(entry.getKey().toString(), convertValue(rsc.getType(), entry.getValue().getValue()));
}
element.put("kind", "multiResource");
element.put("values", values);
element.put("type", rsc.getType());
} else {
element.put("kind", "singleResource");
element.put("type", rsc.getType());
if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
element.put("value", new String(Hex.encodeHex((byte[]) rsc.getValue())));
} else {
element.put("value", rsc.getValue());
}
element.put("value", convertValue(rsc.getType(), rsc.getValue()));
}
} else if (src instanceof LwM2mResourceInstance) {
element.put("kind", "resourceInstance");
LwM2mResourceInstance rsc = (LwM2mResourceInstance) src;
element.put("type", rsc.getType());
if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
element.put("value", new String(Hex.encodeHex((byte[]) rsc.getValue())));
} else {
element.put("value", rsc.getValue());
}
element.put("value", convertValue(rsc.getType(), rsc.getValue()));

}

gen.writeObject(element);
}

private Object convertValue(Type type, Object value) {
switch (type) {
case OPAQUE:
return new String(Hex.encodeHex((byte[]) value));
case INTEGER:
// we use String for INTEGER because
// Javascript number does not support safely number larger than Number.MAX_SAFE_INTEGER (2^53 - 1)
// without usage of BigInt...
return value.toString();
default:
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import BooleanValueInput from "./BooleanValueInput.vue";
import DateTimeValueInput from "./DateTimeValueInput.vue";
import OpaqueValueInput from "./OpaqueValueInput.vue";
import { isInteger, isNumber } from "../../../js/utils.js";
import { isNumber } from "../../../js/utils.js";
import ObjLinkValueInput from './ObjLinkValueInput.vue';

/**
Expand All @@ -66,9 +66,6 @@ export default {
var val = strValue;
if (this.resourcedef.type != undefined) {
switch (this.resourcedef.type) {
case "integer":
val = isInteger(strValue) ? Number(val) : strValue;
break;
case "float":
val = isNumber(val) ? Number(val) : strValue;
break;
Expand Down

0 comments on commit ea3c84a

Please sign in to comment.