ObjectWrapper Conversion

Per this comment:

I am working on a simplified script to convert nested ObjectWrappers into pure python objects. I was guessing that maybe javaToJson might be the way to do it, but I am getting a malformedJson error.

MalformedJson Exception
com.inductiveautomation.ignition.common.script.JythonExecException
Traceback (most recent call last):
  File "<function:runAction>", line 6, in runAction
  File "<function:runAction>", line 4, in convertObj
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:65)
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:45)
	at com.inductiveautomation.ignition.common.JsonUtilities.javaToJson(JsonUtilities.java:660)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
com.inductiveautomation.ignition.common.gson.JsonSyntaxException: com.inductiveautomation.ignition.common.gson.JsonSyntaxException: com.inductiveautomation.ignition.common.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $

	at org.python.core.Py.JavaError(Py.java:547)
	at org.python.core.Py.JavaError(Py.java:538)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:208)
	at org.python.core.PyObject.__call__(PyObject.java:461)
	at org.python.core.PyObject.__call__(PyObject.java:465)
	at org.python.pycode._pyx221.convertObj$2(<function:runAction>:4)
	at org.python.pycode._pyx221.call_function(<function:runAction>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:134)
	at org.python.core.PyFunction.__call__(PyFunction.java:416)
	at org.python.pycode._pyx221.runAction$1(<function:runAction>:8)
	at org.python.pycode._pyx221.call_function(<function:runAction>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
	at org.python.core.PyFunction.function___call__(PyFunction.java:474)
	at org.python.core.PyFunction.__call__(PyFunction.java:469)
	at org.python.core.PyFunction.__call__(PyFunction.java:464)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:839)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:821)
	at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:828)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ScriptFunctionImpl.invoke(ScriptManager.java:1002)
	at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$AutoRecompilingScriptFunction.invoke(ProjectScriptLifecycle.java:893)
	at com.inductiveautomation.perspective.gateway.script.ScriptFunctionHelper.invoke(ScriptFunctionHelper.java:147)
	at com.inductiveautomation.perspective.gateway.action.ScriptAction.runAction(ScriptAction.java:74)
	at com.inductiveautomation.perspective.gateway.model.ActionCollection$ActionSequence$ExecuteActionsTask.lambda$call$0(ActionCollection.java:263)
	at com.inductiveautomation.perspective.gateway.api.LoggingContext.mdc(LoggingContext.java:54)
	at com.inductiveautomation.perspective.gateway.model.ActionCollection$ActionSequence$ExecuteActionsTask.call(ActionCollection.java:252)
	at com.inductiveautomation.perspective.gateway.model.ActionCollection$ActionSequence$ExecuteActionsTask.call(ActionCollection.java:221)
	at com.inductiveautomation.perspective.gateway.threading.BlockingTaskQueue$TaskWrapper.run(BlockingTaskQueue.java:154)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at com.inductiveautomation.perspective.gateway.threading.BlockingWork$BlockingWorkRunnable.run(BlockingWork.java:58)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException
Traceback (most recent call last):
  File "<function:runAction>", line 6, in runAction
  File "<function:runAction>", line 4, in convertObj
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:65)
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:45)
	at com.inductiveautomation.ignition.common.JsonUtilities.javaToJson(JsonUtilities.java:660)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
com.inductiveautomation.ignition.common.gson.JsonSyntaxException: com.inductiveautomation.ignition.common.gson.JsonSyntaxException: com.inductiveautomation.ignition.common.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $

	... 36 more
Caused by: com.inductiveautomation.ignition.common.gson.JsonSyntaxException
com.inductiveautomation.ignition.common.GenericTransferrableException: com.inductiveautomation.ignition.common.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:65)
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:45)
	at com.inductiveautomation.ignition.common.JsonUtilities.javaToJson(JsonUtilities.java:660)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
	... 33 more
Caused by: com.inductiveautomation.ignition.common.gson.stream.MalformedJsonException
com.inductiveautomation.ignition.common.GenericTransferrableException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $
	at com.inductiveautomation.ignition.common.gson.stream.JsonReader.syntaxError(JsonReader.java:1568)
	at com.inductiveautomation.ignition.common.gson.stream.JsonReader.checkLenient(JsonReader.java:1409)
	at com.inductiveautomation.ignition.common.gson.stream.JsonReader.doPeek(JsonReader.java:542)
	at com.inductiveautomation.ignition.common.gson.stream.JsonReader.peek(JsonReader.java:425)
	at com.inductiveautomation.ignition.common.gson.JsonParser.parse(JsonParser.java:60)
	... 40 more

Ignition v8.1.18 (b2022061518)
Java: Azul Systems, Inc. 11.0.15

Often we need to serialize deeply-nested Perspective properties into Json so that we can store them in a database.

The test object I am trying to convert is:

{
  "myVar": "value",
  "myNestedObj": {
    "myVal": 1,
    "myArr": [
      "value1",
      "value2"
    ]
  }
}

Looking through the above-mentioned JsonUtilities class I am not seeing anything obvious.

I appreciate any ideas on how to more affectively convert over these ObjectWrappers!

you can use system.util.jsonEncode
https://docs.inductiveautomation.com/display/DOC81/system.util.jsonEncode

Most of the JsonUtilities methods expect you to already have a typed gson JsonElement instance, since that's how we represent JSON objects in Java code internally.

TypeUtilities has pyToGson and gsonToPy methods that will do the conversion for you.

I mentioned it as an offhand thing; some of the utilities in there aren't going to be super 'idiomatic' to use from Python, but stuff like iterating via a JsonPath is probably nicer to rely on our internal implementation than having to make yourself.

2 Likes