# Resolving Equality for PyJsonObjectAdapter

**URL:** <https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334>\
**Category:** Ignition\
**Tags:** ignition83\
**Created:** [October 5, 2026, 3:42pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334 "2026-10-05T15:42:40Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Noah\_Burnette](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/noah_burnette/32/83777_2.png) [@Noah\_Burnette](https://forum.inductiveautomation.com/u/Noah_Burnette)\
**Post date:** [October 5, 2026, 3:42pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/1 "2026-10-05T15:42:41Z")

</div>

Hey everyone,

I am trying to check a diff between a previous tag value and current tag value in event streams and I'm running into issues with the equality semantics. I am pointing the tag source to an aggregation of tags via `jsonvalues` to be sent to external systems. I essentially need to filter out the aggregates that _only_ have noisy tag changes like a heartbeat tag.

Without encoding and decoding from json (performance reasons) or recursively checking each field, is there a way to get a proper equality comparison? I'm hoping I am just missing something.

Example script:

```python
from com.inductiveautomation.ignition.common.gson import JsonObject
from com.inductiveautomation.ignition.common.script.adapters import PyJsonObjectAdapter

# Assuming this is the correct way to construct PyJsonObjectAdapter to mimic Event Stream object type
jsonObject1 = JsonObject()
jsonObject1.addProperty("State", "Running")
jsonObject1.addProperty("Mode", "Auto")

jsonObject2 = JsonObject()
jsonObject2.addProperty("State", "Running")
jsonObject2.addProperty("Mode", "Auto")

value1 = PyJsonObjectAdapter(jsonObject1)
value2 = PyJsonObjectAdapter(jsonObject2)

print "value1 type: {}".format(type(value1))
print "value2 type: {}".format(type(value2))
print "value1: {}".format(value1)
print "value2: {}".format(value2)
# Expected false
print "Same object: {}".format(value1 is value2)
# Expected true based on contents. Seems as though it is falling back to identity comparison
print "'Python' equality: {}".format(value1 == value2)

print "---"
print "Field comparison:"
print "State equal: {}".format(value1["State"] == value2["State"])
print "Mode equal: {}".format(value1["Mode"] == value2["Mode"])

```

Output:

```plaintext
value1 type: <type 'com.inductiveautomation.ignition.common.script.adapters.PyJsonObjectAdapter'>
value2 type: <type 'com.inductiveautomation.ignition.common.script.adapters.PyJsonObjectAdapter'>
value1: {"State":"Running","Mode":"Auto"}
value2: {"State":"Running","Mode":"Auto"}
Same object: 0
'Python' equality: 0
---
Field comparison:
State equal: 1
Mode equal: 1

```

Javadoc reference:

> **[PyJsonObjectAdapter](https://sdk.inductiveautomation.com/javadoc/ignition83/8.3.9/com/inductiveautomation/ignition/common/script/adapters/PyJsonObjectAdapter.html)**
>
> declaration: package: com.inductiveautomation.ignition.common.script.adapters, class: PyJsonObjectAdapter

EDIT:

Found the implementation for ` __eq__ ` that `PyJsonObjectAdapter` inherits from.

> <https://github.com/jython/jython/blob/1788fd2572e32d7ed026f5409be77a917b01a578/src/org/python/core/PyObject.java>

Any pointers much appreciated!

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 5, 2026, 4:18pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/2 "2026-10-05T16:18:58Z")

</div>

> [@Noah\_Burnette](#):
>
> recursively checking each field

How else could a structural equality comparison work?

If you want deep equals, you have to do the recursive traversal.

If you can express your algorithm more cheaply or via a shortcut (e.g. only compare equality on keys) it's easy enough to write that out yourself.

In theory, if you can get the underlying JsonObject out of the adapter, you can use the equals method on it directly, which at least saves you writing the recursion yourself.

---

<div class="post-metadata">

**Author:** ![Noah\_Burnette](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/noah_burnette/32/83777_2.png) [@Noah\_Burnette](https://forum.inductiveautomation.com/u/Noah_Burnette)\
**Post date:** [October 5, 2026, 4:48pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/3 "2026-10-05T16:48:45Z")

</div>

> [@paul-griffith](#):
>
> saves you writing the recursion yourself.

That's my goal 😃 thanks!

---

<div class="post-metadata">

**Author:** ![Noah\_Burnette](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/noah_burnette/32/83777_2.png) [@Noah\_Burnette](https://forum.inductiveautomation.com/u/Noah_Burnette)\
**Post date:** [October 7, 2026, 1:35pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/4 "2026-10-07T13:35:50Z")

</div>

In case anyone runs into this later:

```python
from com.inductiveautomation.ignition.common.gson import JsonObject
from com.inductiveautomation.ignition.common.script.adapters import PyJsonObjectAdapter

jsonObject1 = JsonObject()
jsonObject1.addProperty("State", "Running")
jsonObject1.addProperty("Mode", "Auto")

jsonObject2 = JsonObject()
jsonObject2.addProperty("State", "Running")
jsonObject2.addProperty("Mode", "Auto")

value1 = PyJsonObjectAdapter(jsonObject1)
value2 = PyJsonObjectAdapter(jsonObject2)

# Python equality check (expected false)
value1 == value2
# Native JsonObject equality check (expected true)
JsonObject.equals(value1, value2)

```

Output:

```plaintext
>>> 
False
True

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 7, 2026, 3:59pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/5 "2026-10-07T15:59:54Z")

</div>

Huh, that's clever. I would not have thought to do that.  
As far as I can tell that only works through some fairly impressive Jython machinery; it's calling the instance method of `JsonObject` as if it were static because you passed in an instance to use as `self`, and the first instance you passed only works because it's automatically "unwrapping" the object adapter.

Fascinating.

---

<div class="post-metadata">

**Author:** ![AIO](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/aio/32/87549_2.png) [@AIO](https://forum.inductiveautomation.com/u/AIO)\
**Post date:** [October 7, 2026, 5:48pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/6 "2026-10-07T17:48:21Z")

</div>

I love reading posts that make Paul say "Fascinating."

---

<div class="post-metadata">

**Author:** ![Noah\_Burnette](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/noah_burnette/32/83777_2.png) [@Noah\_Burnette](https://forum.inductiveautomation.com/u/Noah_Burnette)\
**Post date:** [October 7, 2026, 8:24pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/7 "2026-10-07T20:24:05Z")

</div>

Okay, just upgraded from `8.3.7` to `8.3.10` and the assumption that `event.data.value` and `event.metadata.previousValue.value` are both `PyJsonObjectAdapter` is not true anymore ☹

**8.3.7 Behavior:**

- `event.data.value` is a `PyJsonObjectAdapter`
- `event.metadata.previousValue.value` is a `PyJsonObjectAdapter`

**8.3.10 Behavior:**

- `event.data.value` is a `PyJsonObjectAdapter`
- `event.metadata.previousValue.value` is a `java.util.HashMap`
- `event.metadata.previousValue` can no longer reference `value` in dot notation but rather you have to use the key lookup i.e. `["somekey"]`.

Workaround:

- Use key lookup for `previousValue`
- Cast `event.data.value` to a HashMap to do a comparison

My filtering code is completely broken on the dev server that I upgraded while the production servers that are on `8.3.7` are still properly filtering. This looks like a regression to me or undocumented behavior change. I will open a ticket with support to make sure.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 7, 2026, 10:36pm UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/8 "2026-10-07T22:36:51Z")

</div>

It was 8.3.8, under an umbrella of changes to improve event stream performance. It'll be stable going forward - the change was justified under the logic that previously `metadata` was mutable which was fully incorrect.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 8, 2026, 10:06am UTC](https://forum.inductiveautomation.com/t/resolving-equality-for-pyjsonobjectadapter/117334/9 "2026-10-08T10:06:58Z")

</div>

> [@paul-griffith](#):
>
> Fascinating.

Live long and prosper.
