Hash DynamicUnionType by its DataType's NodeId - #1954
Merged
kevinherron merged 1 commit intoSep 8, 2026
Conversation
DynamicUnionType.equals compares the DataType by NodeId, because DataType implementations are not required to define equals()/hashCode() and several do not, but hashCode hashed the DataType object itself. Two DynamicUnionType values built from distinct DataType instances describing the same DataType are therefore equal with different hashes, and a lookup for one does not find the other. The sibling classes written alongside it already do this: DynamicStructType and DynamicEnumType both hash dataType.getNodeId(). Hash the NodeId too. Nothing else changes; when both values share a DataType instance the hash is the same as before. Signed-off-by: alxkm <alexanderklmn@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DynamicUnionType.equalscompares the DataType by NodeId:DataTypeimplementations are not required to defineequals/hashCode, and several do not —BsdDataTypeandDictionaryDataTypebothimplements DataTypewithout either, so they hash byidentity. Two
DynamicUnionTypevalues built from distinctDataTypeinstances describing thesame DataType are then equal with different hashes:
The two sibling classes written alongside it already hash the NodeId:
Scope
Within a single
DataTypeTreethis does not bite:TypeTreeholds aMap<NodeId, Tree<T>>, sogetDataType(id)returns the same instance every time and the hash is stable. It bites when theinstances differ — a rebuilt DataTypeTree, or a DataType constructed separately. Nothing in the
repository puts a
DynamicUnionTypeinto a hash-based collection today, so this is a public APIcontract fix rather than a fix for a broken internal path.
Change
Hash
dataType.getNodeId()instead ofdataType, matchingequalsand the two siblings. Whenboth values share a DataType instance the hash is unchanged.
Tests
DynamicUnionTypeTest.equalUnionsHashTheSamefails before the change and passes after:It uses the existing
AbstractDataTypetest helper, which defines noequals/hashCode, to buildtwo distinct DataType instances with the same NodeId.
DynamicUnionTypeTest.unionsWithDifferentValuesAreNotEqualis added as a guard that the changedoes not make unrelated unions compare equal.
Verified on JDK 17 with
mvn -pl opc-ua-sdk/integration-tests -am verify: all 14 modules pass —2329 tests, 0 failures, 0 errors — including
spotless:checkand Checkstyle.