Search code examples
javaopc-uamilo

How to correctly work with ExtensionObject and Struct in milo opc ua


I would like to ask how should I work correctly with Struct when I am trying to read some object from opc ua server. I went trough this example and I was able to read the data.

But right now I don't know how to correctly read them. Let's imagine I am reading some datastructure including two arrays for x and y values. I tried to do something like this:

 Float[] x = (Float[])struct.getMember("x").getValue()
 Float[] y = (Float[])struct.getMember("y").getValue()

but I receive exception "Cannot cast 'java.lang.Object[]' to 'java.lang.Float[]'" I am able to do it this way:

float[] x = new float[100];
        int i = 0;
        for(Object o: (Object[])struct.getMember("x").getValue()){
            x[i] = (Float)o;
            i++;
        }

but I don't think this could be right.

Anyway I would like to achieve something similar like reading json file with jackson. To have some class with same naming asi the "members are and with suitable types and do something like:

OpcuaReader reader = ...
MyClass myClass = reader.read(struct, MyClass.class)

I could be totally wrong so could anyone suggest me how should I solve such problem?


Solution

  • First of all, you cannot cast array of objects like that. Instead, you could use the stream API to construct Floats like this:

    Object[] objectArray = { 1.0f, 2.0f, 3, 4, 5 };
    Float floatArray[] = Arrays.stream(objectArray)
      .map(Object::toString)
      .map(Float::valueOf)
      .toArray(Float[]::new);
    

    About the Milo client, there is a great example of reading custom data types in ReadWriteCustomDataTypeNodeExample.

    You can create your own type similar to CustomStructType and override the decode method for yourself. The decoder also has a built in readFloatArray method in hand:

    @Override
    public CustomStructType decode(
        SerializationContext context,
        UaDecoder decoder) throws UaSerializationException {
    
        String foo = decoder.readString("Foo");
        UInteger bar = decoder.readUInt32("Bar");
        boolean baz = decoder.readBoolean("Baz");
    
        Float[] floatArray = decoder.readFloatArray("floatArray");
    
        return new CustomStructType(foo, bar, baz);
    }