Skip to content

Commit f535815

Browse files
committed
~ fix serialization of structs with scalar abstract fields
1 parent a93149b commit f535815

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

opc-ua-sdk/sdk-core/src/main/java/org/eclipse/milo/opcua/sdk/core/types/DynamicStructCodec.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.eclipse.milo.opcua.sdk.core.typetree.DataType;
2323
import org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree;
2424
import org.eclipse.milo.opcua.stack.core.BuiltinDataType;
25+
import org.eclipse.milo.opcua.stack.core.NodeIds;
2526
import org.eclipse.milo.opcua.stack.core.StatusCodes;
2627
import org.eclipse.milo.opcua.stack.core.UaSerializationException;
2728
import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext;
@@ -263,7 +264,12 @@ private Object decodeFieldValue(UaDecoder decoder, StructureField field) {
263264
break;
264265
}
265266
case STRUCT:
266-
value = decoder.decodeStruct(fieldName, dataTypeId);
267+
if (dataTypeId.equals(NodeIds.Structure) || fieldAllowsSubtyping(field)) {
268+
ExtensionObject xo = decoder.decodeExtensionObject(fieldName);
269+
value = xo.decode(decoder.getEncodingContext());
270+
} else {
271+
value = decoder.decodeStruct(fieldName, dataTypeId);
272+
}
267273
break;
268274
default:
269275
throw new RuntimeException("codecType: " + typeHint);
@@ -356,7 +362,14 @@ private void encodeFieldValue(UaEncoder encoder, StructureField field, Object va
356362
encoder.encodeEnum(fieldName, (UaEnumeratedType) value);
357363
break;
358364
case STRUCT:
359-
encoder.encodeStruct(fieldName, value, dataTypeId);
365+
if (dataTypeId.equals(NodeIds.Structure) || fieldAllowsSubtyping(field)) {
366+
DynamicStruct structValue = (DynamicStruct) value;
367+
ExtensionObject xo =
368+
ExtensionObject.encode(encoder.getEncodingContext(), structValue);
369+
encoder.encodeExtensionObject(fieldName, xo);
370+
} else {
371+
encoder.encodeStruct(fieldName, value, dataTypeId);
372+
}
360373
break;
361374
default:
362375
throw new RuntimeException("codecType: " + typeHint);
@@ -406,6 +419,20 @@ private void encodeFieldValue(UaEncoder encoder, StructureField field, Object va
406419
}
407420
}
408421

422+
/**
423+
* Check if the field allows subtyping.
424+
*
425+
* <p>In Structures and Unions this means the field is encoded as an ExtensionObject.
426+
*
427+
* @param field the {@link StructureField} to check.
428+
* @return {@code true} if the field allows subtyping.
429+
*/
430+
private boolean fieldAllowsSubtyping(StructureField field) {
431+
return field.getIsOptional()
432+
&& (definition.getStructureType() == StructureType.StructureWithSubtypedValues
433+
|| definition.getStructureType() == StructureType.UnionWithSubtypedValues);
434+
}
435+
409436
private static Object decodeBuiltinDataType(
410437
UaDecoder decoder, String fieldName, BuiltinDataType builtinDataType) {
411438

0 commit comments

Comments
 (0)