[ 
https://issues.apache.org/jira/browse/PLC4X-201?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17119390#comment-17119390
 ] 

Alessandro Rossignoli commented on PLC4X-201:
---------------------------------------------

Ok I have found a workaround to interface Eclipse Milo with PlcList, but I 
would like to discuss this with you and check it this is correct way.

As a first solution I have added a workaround in the write section of the 
OpcuaTcpPlcConnection (line 430) 
[https://github.com/apache/plc4x/blob/6b2b3ca38cd36b7be1d7d4e4ee171508b155339b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaTcpPlcConnection.java#L454],
 as it has been done for BigInteger type.
{code:java}
if (valueObject instanceof List) { 
  valueObject = 
this.getPlainArrayFromCollection(internalPlcWriteRequest.getPlcValue(fieldName).getList());
 
}
{code}
 

Then the method I have implemented is the following,  based on the assertion 
that Lists are homogeneous (this is granted by the checks made here: 
[[#https://github.com/apache/plc4x/blob/4a74ff526aeb57e978005e37c878fe55021462aa/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java#L251]|https://github.com/apache/plc4x/blob/4a74ff526aeb57e978005e37c878fe55021462aa/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java#L251]
{code:java}
private Object[] getPlainArrayFromCollection(List<? extends PlcValue> list) {
    if (!list.isEmpty()) {
        Object firstElem = list.get(0);

        if (firstElem instanceof PlcBoolean) {
            return convertPlcListToArray(Boolean.class, list);
        } else if (firstElem instanceof PlcByte) {
            return convertPlcListToArray(Byte.class, list);
        } else if (firstElem instanceof PlcShort) {
            return convertPlcListToArray(Short.class, list);
        } else if (firstElem instanceof PlcInteger) {
            return convertPlcListToArray(Integer.class, list);
        } else if (firstElem instanceof PlcLong) {
            return convertPlcListToArray(Long.class, list);
        } else if (firstElem instanceof PlcFloat) {
            return convertPlcListToArray(Float.class, list);
        } else if (firstElem instanceof PlcDouble) {
            return convertPlcListToArray(Double.class, list);
        } else if (firstElem instanceof PlcString) {
            return convertPlcListToArray(String.class, list);
        } else {
            return list.toArray(new Object[list.size()]);
        }
    } else {
        return new Object[0];
    }
}
{code}
In this way I am able to start from a List<T> where T extends PlcValue (note 
that there are not flatten methods for the List<List<T>> but I think it is a 
corner case that is very very uncommon for now).

In order to get the T[] I need to pass to Eclipse Milo I have written this 
method:
{code:java}
private <T> T[] convertPlcListToArray(Class<T> clazz, List<? extends PlcValue> 
list) {
    if (!list.isEmpty()) {
        T[] ret = (T[]) Array.newInstance(clazz, list.size());

        for (int i = 0; i < ret.length; i++) {
            ret[i] = (T) list.get(i).getObject();
        }
        return ret;
    } else {
        return null;
    }
}
{code}
In this way I can get the array written to my node in the OPC-UA server.

 

This is a possible fix, not very structured to be honest but working. Another 
solution that could be implemented probably smarter than what I did is to 
change PlcList class by making it generic-type aware.

Something like this to let you better get the idea:
{code:java}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
public class PlcList<T> extends PlcValueAdapter {

    private final List<PlcValue> listItems;
    private final Class<T> internalClass;

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public PlcList(@JsonProperty("listItems") List<?> listItems, Class<T> 
internalClass) {
        this.internalClass = internalClass;

        List<PlcValue> safelist = listItems.stream().map(plcValue -> {
            // to avoid unwrapped list cause of type erasure
            if (plcValue instanceof PlcValue) {
                return (PlcValue) plcValue;
            } else {
                return PlcValues.of(plcValue);
            }
        }).collect(Collectors.toList());
        this.listItems = Collections.unmodifiableList(safelist);
    }

    @Override
    public Object getObject() {
        return (T[])Array.newInstance(internalClass, listItems.size());
    }

{code}
The latter is the one I prefer, since it is cleaner and probably more logical. 
The problem is that I don't have a clear understanding of the whole library and 
I don't know how many things the latter could break, while the first proposed 
solution is more a "patch".

 

Let me know what you think could be the best fit for plc4x. 

 

 

> OPC-UA PlcList underlying type not compatible with Eclipse Milo
> ---------------------------------------------------------------
>
>                 Key: PLC4X-201
>                 URL: https://issues.apache.org/jira/browse/PLC4X-201
>             Project: Apache PLC4X
>          Issue Type: Bug
>          Components: Driver-OPC-UA
>    Affects Versions: 0.7.0
>            Reporter: Alessandro Rossignoli
>            Priority: Major
>              Labels: beginner
>
> java.util.Collections$UnmodifiableRandomAccessList is not compatible with 
> Eclipse Milo built-in types.
> When writing to the OPC-UA driver a simple array of Double, I receive the 
> following error:
> [org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamEncoder:608]:
>  Not a built-in type: class java.util.Collections$UnmodifiableRandomAccessList
> When writing a single value in the array the type is PlcDouble instead of 
> PlcList, and there is no error.
>  
> I think that a possible solution could be changing the underlying type, or 
> better to change the getter for the value.
> [https://github.com/apache/plc4x/blob/4a74ff526aeb57e978005e37c878fe55021462aa/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java#L46]
> I will try to find myself a solution and I will keep you posted.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to