Skip to content
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

leshan-server-demo, current master, LwM2mNodeDeserializer.java IllegalStateException("This is not a JSON Primitive.") on opaque #799

Closed
strautins opened this issue Feb 4, 2020 · 5 comments
Labels
question Any question about leshan

Comments

@strautins
Copy link

Leshan-server-demo, current master, LwM2mNodeDeserializer.java IllegalStateException("This is not a JSON Primitive.") on opaque value

Deserializing opaque values throws IllegalStateException("This is not a JSON Primitive.").
As far as I know, this works.
Added function

private byte[] getOpaque(JsonDeserializationContext context, JsonElement element) {
        try {
            return Hex.decodeHex((char[]) context.deserialize(element, char[].class));
        } catch (Exception e) {
            return null;
        }
}

and changed code from

...
 } else if (object.has("value")) {
	// single value resource
	JsonPrimitive val = object.get("value").getAsJsonPrimitive();
	org.eclipse.leshan.core.model.ResourceModel.Type expectedType = getTypeFor(val);
	node = LwM2mSingleResource.newResource(id, deserializeValue(val, expectedType), expectedType);
} else if (object.has("values")) {
	// multi-instances resource
	Map<Integer, Object> values = new HashMap<>();
	org.eclipse.leshan.core.model.ResourceModel.Type expectedType = null;
	for (Entry<String, JsonElement> entry : object.get("values").getAsJsonObject().entrySet()) {
		JsonPrimitive pval = entry.getValue().getAsJsonPrimitive();
		expectedType = getTypeFor(pval);
		values.put(Integer.valueOf(entry.getKey()), deserializeValue(pval, expectedType));
	}
	// use string by default;
	if (expectedType == null)
		expectedType = org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
	node = LwM2mMultipleResource.newResource(id, values, expectedType);
} else {
...

to

...
} else if (object.has("value")) {
	// single value resource
	Object objVal;
	org.eclipse.leshan.core.model.ResourceModel.Type expectedType = null;
	JsonElement element = object.get("value");
	if(element.isJsonPrimitive()) {
		JsonPrimitive val = element.getAsJsonPrimitive();
		expectedType = getTypeFor(val);
		objVal = deserializeValue(val, expectedType);
	} else {
		objVal = getOpaque(context, element);
		expectedType = org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
	}
	node = LwM2mSingleResource.newResource(id, objVal, expectedType);
} else if (object.has("values")) {
	// multi-instances resource
	Map<Integer, Object> values = new HashMap<>();
	org.eclipse.leshan.core.model.ResourceModel.Type expectedType = null;
	for (Entry<String, JsonElement> entry : object.get("values").getAsJsonObject().entrySet()) {
		Object objVal;
		if(entry.getValue().isJsonPrimitive()) {
			JsonPrimitive pval = entry.getValue().getAsJsonPrimitive();
			expectedType = getTypeFor(pval);
			objVal = deserializeValue(pval, expectedType);
		} else {
			objVal = getOpaque(context, entry.getValue());
			expectedType = org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
		}
		values.put(Integer.valueOf(entry.getKey()), objVal);
	}
	// use string by default;
	if (expectedType == null)
		expectedType = org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
	node = LwM2mMultipleResource.newResource(id, values, expectedType);
} else {
...

If you have time to check and upgrade leshan server demo deserializer it would be nice.
This is only info for others, you can close this isue ;)

@sbernard31
Copy link
Contributor

I'm not sure to get you point.

It seems you want to write an opaque value, right ?

Currently to do that you need to send a payload like this :

{"id":0,"value":"012ABC"}

And you would like to be able to do something like this ?

{"id":0,"value":["0","1","2","a","b","c"]}

If,I'm right. Could you explain why ?

@strautins
Copy link
Author

I am not sending payload.
Using

  GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeHierarchyAdapter(LwM2mNode.class, new LwM2mNodeSerializer());
        gsonBuilder.registerTypeHierarchyAdapter(LwM2mNode.class, new LwM2mNodeDeserializer());
        gsonBuilder.setDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        this.gson = gsonBuilder.create();

and then

String response = this.gson.toJson(lwm2mObject);

and then there is error

LwM2mObject obj = this.gson.fromJson(response , LwM2mObject.class);

LwM2mNodeSerializer.java already creating char[] from OPAQUE type, I am just added decode what was missing.

Code from LwM2mNodeSerializer.java

...
if (rsc.isMultiInstances()) {
	JsonObject values = new JsonObject();
	for (Entry<Integer, ?> entry : rsc.getValues().entrySet()) {
		if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
			values.add(entry.getKey().toString(),
					context.serialize(Hex.encodeHex((byte[]) entry.getValue())));
		} else {
			values.add(entry.getKey().toString(), context.serialize(entry.getValue()));
		}
	}
	element.add("values", values);
} else {
	if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
		element.add("value", context.serialize(Hex.encodeHex((byte[]) rsc.getValue())));
	} else {
		element.add("value", context.serialize(rsc.getValue()));
	}
}
...

So sequence is like this.. I serialize Lwm2mObject where is opaque values and when I want to deserialize this object, then I get IllegalStateException. char[] is not a JsonPrimitive.

@sbernard31
Copy link
Contributor

OK I get you point.

You just want to make LwM2mNodeDeserializer and LwM2mNodeSerializer consistent.

As the rest API :

  • LwM2mNodeDeserializer is only used for demo REST API.
  • REST API is just needed for demo UI.
  • demo UI doesn't use char array for OPAQUE.
  • and demo is not really intended to be reused.

I'm not sure to see why this is needed ? but we can add it if this helps.

@strautins
Copy link
Author

Oh, ok, I am using this to store / cache and later retrieve objects. Do stuff, check previous values etc.
Was lazy to manual serialize info I need. I already fixed for myself, no need to worry. thanks.

@sbernard31
Copy link
Contributor

#806 will now encode Opaque value as an hexa string. This is more consistent.

@sbernard31 sbernard31 added the question Any question about leshan label Feb 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Any question about leshan
Projects
None yet
Development

No branches or pull requests

2 participants