This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch feat/improved-s7-opcua-support
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 3dc0976cf61f8ef1ba3a8ceb95611ecaf24ace84
Author: Christofer Dutz <[email protected]>
AuthorDate: Sun Feb 22 19:07:41 2026 +0100

    chore: Added a test for my S7-1500 opcua setup and did some minor tweaks to 
support reading and writing most types on this PLC.
---
 .../apache/plc4x/java/opcua/OpcuaPlcDriver.java    |   7 -
 .../java/opcua/protocol/OpcuaProtocolLogic.java    |  51 ++--
 .../opcua/ManualOpcUaS71500NewFWDriverTest.java    | 149 ++++++++++++
 .../java/spi/values/DefaultPlcValueHandler.java    |  18 +-
 .../java/spi/values/LegacyPlcValueHandler.java     | 264 ---------------------
 5 files changed, 187 insertions(+), 302 deletions(-)

diff --git 
a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
 
b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
index a1200481b7..6043a3ba0f 100644
--- 
a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
+++ 
b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
@@ -29,8 +29,6 @@ import org.apache.plc4x.java.opcua.tag.OpcuaTag;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
 import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer;
-import org.apache.plc4x.java.spi.values.LegacyPlcValueHandler;
-import org.apache.plc4x.java.spi.values.PlcValueHandler;
 
 import java.util.Collections;
 import java.util.List;
@@ -64,11 +62,6 @@ public class OpcuaPlcDriver extends 
GeneratedDriverBase<OpcuaAPU> {
         return Collections.singletonList("tcp");
     }
 
-    @Override
-    protected PlcValueHandler getValueHandler() {
-        return new LegacyPlcValueHandler();
-    }
-
     @Override
     protected boolean canRead() {
         return true;
diff --git 
a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
 
b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
index 41d8c94cd7..6b804959db 100644
--- 
a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
+++ 
b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
@@ -22,6 +22,7 @@ import static 
org.apache.plc4x.java.opcua.context.SecureChannel.getX509Certifica
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.time.*;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.plc4x.java.api.authentication.PlcAuthentication;
@@ -50,7 +51,6 @@ import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
 import org.apache.plc4x.java.spi.connection.PlcTagHandler;
 import org.apache.plc4x.java.spi.context.DriverContext;
-import org.apache.plc4x.java.spi.generation.Message;
 import org.apache.plc4x.java.spi.messages.*;
 import org.apache.plc4x.java.spi.messages.utils.DefaultPlcResponseItem;
 import org.apache.plc4x.java.spi.messages.utils.PlcResponseItem;
@@ -59,17 +59,12 @@ import 
org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
 import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionTag;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
 import 
org.apache.plc4x.java.spi.transaction.RequestTransactionManager.RequestTransaction;
-import org.apache.plc4x.java.spi.values.LegacyPlcValueHandler;
+import org.apache.plc4x.java.spi.values.DefaultPlcValueHandler;
 import org.apache.plc4x.java.spi.values.PlcList;
-import org.apache.plc4x.java.spi.values.PlcSTRING;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.math.BigInteger;
-import java.time.Duration;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;
@@ -319,44 +314,44 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = array[i] != 0;
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantSByte) {
             byte[] array = ((VariantSByte) variant).getValue();
-            value = LegacyPlcValueHandler.of(tag, array);
+            value = DefaultPlcValueHandler.of(tag, array);
         } else if (variant instanceof VariantByte) {
             List<Short> array = ((VariantByte) variant).getValue();
             Short[] tmpValue = array.toArray(new Short[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantInt16) {
             List<Short> array = ((VariantInt16) variant).getValue();
             Short[] tmpValue = array.toArray(new Short[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantUInt16) {
             List<Integer> array = ((VariantUInt16) variant).getValue();
             Integer[] tmpValue = array.toArray(new Integer[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantInt32) {
             List<Integer> array = ((VariantInt32) variant).getValue();
             Integer[] tmpValue = array.toArray(new Integer[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantUInt32) {
             List<Long> array = ((VariantUInt32) variant).getValue();
             Long[] tmpValue = array.toArray(new Long[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantInt64) {
             List<Long> array = ((VariantInt64) variant).getValue();
             Long[] tmpValue = array.toArray(new Long[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantUInt64) {
-            value = LegacyPlcValueHandler.of(((VariantUInt64) 
variant).getValue());
+            value = DefaultPlcValueHandler.of(tag, ((VariantUInt64) 
variant).getValue());
         } else if (variant instanceof VariantFloat) {
             List<Float> array = ((VariantFloat) variant).getValue();
             Float[] tmpValue = array.toArray(new Float[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantDouble) {
             List<Double> array = ((VariantDouble) variant).getValue();
             Double[] tmpValue = array.toArray(new Double[0]);
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantString) {
             int length = ((VariantString) variant).getValue().size();
             List<PascalString> stringArray = ((VariantString) 
variant).getValue();
@@ -364,7 +359,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = stringArray.get(i).getStringValue();
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantDateTime) {
             List<Long> array = ((VariantDateTime) variant).getValue();
             int length = array.size();
@@ -372,7 +367,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = 
LocalDateTime.ofInstant(Instant.ofEpochMilli(getDateTime(array.get(i))), 
ZoneOffset.UTC);
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantGuid) {
             List<GuidValue> array = ((VariantGuid) variant).getValue();
             int length = array.size();
@@ -391,7 +386,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
                 }
                 tmpValue[i] = Long.toHexString(array.get(i).getData1()) + "-" 
+ Integer.toHexString(array.get(i).getData2()) + "-" + 
Integer.toHexString(array.get(i).getData3()) + "-" + Integer.toHexString(data4) 
+ "-" + Long.toHexString(data5);
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantXmlElement) {
             int length = ((VariantXmlElement) variant).getValue().size();
             List<PascalString> strings = ((VariantXmlElement) 
variant).getValue();
@@ -399,7 +394,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = strings.get(i).getStringValue();
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantLocalizedText) {
             int length = ((VariantLocalizedText) variant).getValue().size();
             List<LocalizedText> strings = ((VariantLocalizedText) 
variant).getValue();
@@ -409,7 +404,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
                 tmpValue[i] += strings.get(i).getLocaleSpecified() ? 
strings.get(i).getLocale().getStringValue() + "|" : "";
                 tmpValue[i] += strings.get(i).getTextSpecified() ? 
strings.get(i).getText().getStringValue() : "";
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantQualifiedName) {
             int length = ((VariantQualifiedName) variant).getValue().size();
             List<QualifiedName> strings = ((VariantQualifiedName) 
variant).getValue();
@@ -417,7 +412,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = "ns=" + strings.get(i).getNamespaceIndex() + 
";s=" + strings.get(i).getName().getStringValue();
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantExtensionObject) {
             int length = ((VariantExtensionObject) variant).getValue().size();
             List<ExtensionObject> strings = ((VariantExtensionObject) 
variant).getValue();
@@ -425,7 +420,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = strings.get(i).toString();
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantNodeId) {
             int length = ((VariantNodeId) variant).getValue().size();
             List<NodeId> strings = ((VariantNodeId) variant).getValue();
@@ -433,7 +428,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = strings.get(i).toString();
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantStatusCode) {
             int length = ((VariantStatusCode) variant).getValue().size();
             List<StatusCode> strings = ((VariantStatusCode) 
variant).getValue();
@@ -441,7 +436,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
             for (int i = 0; i < length; i++) {
                 tmpValue[i] = strings.get(i).toString();
             }
-            value = LegacyPlcValueHandler.of(tmpValue);
+            value = DefaultPlcValueHandler.of(tag, tmpValue);
         } else if (variant instanceof VariantByteString) {
             PlcList plcList = new PlcList();
             List<ByteStringArray> array = ((VariantByteString) 
variant).getValue();
@@ -451,7 +446,7 @@ public class OpcuaProtocolLogic extends 
Plc4xProtocolBase<OpcuaAPU> implements H
                 for (int i = 0; i < length; i++) {
                     tmpValue[i] = byteStringArray.getValue().get(i);
                 }
-                plcList.add(LegacyPlcValueHandler.of(tmpValue));
+                plcList.add(DefaultPlcValueHandler.of(tag, tmpValue));
             }
             value = plcList;
         }
diff --git 
a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualOpcUaS71500NewFWDriverTest.java
 
b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualOpcUaS71500NewFWDriverTest.java
new file mode 100644
index 0000000000..9b7050b038
--- /dev/null
+++ 
b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualOpcUaS71500NewFWDriverTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.java.opcua;
+
+import org.apache.plc4x.java.spi.values.*;
+import org.apache.plc4x.test.manual.ManualTest;
+
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.List;
+
+public class ManualOpcUaS71500NewFWDriverTest extends ManualTest {
+
+    public ManualOpcUaS71500NewFWDriverTest(String connectionString) {
+        super(connectionString, true, true, true, true, 100);
+    }
+
+    public static void main(String[] args) throws Exception {
+        boolean testArrays = false;
+        ManualOpcUaS71500NewFWDriverTest test = new 
ManualOpcUaS71500NewFWDriverTest("opcua://192.168.24.66:4840");
+        test.addTestCase(/*"g_b1",*/            "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_b1\";BOOL",                   new PlcBOOL(true));
+        test.addTestCase(/*"g_b8",*/            "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_b8\";BYTE",                     new PlcBYTE(0xAB));
+        test.addTestCase(/*"g_s8",*/            "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_s8\";SINT",                     new PlcSINT(-12));
+        test.addTestCase(/*"g_u8",*/            "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_u8\";USINT",                    new PlcUSINT(250));
+        // TODO: Getting "INVALID_ADDRESS", as WORD is not part of 
OpcuaDataType
+//        test.addTestCase(/*"g_b16",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_b16\";WORD",                  new PlcWORD(0xBEEF));
+        test.addTestCase(/*"g_s16",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_s16\";INT",                  new PlcINT(-1234));
+        test.addTestCase(/*"g_u16",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_u16\";UINT",                  new PlcUINT(54321));
+        // TODO: Getting "INVALID_ADDRESS", as DWORD is not part of 
OpcuaDataType
+//        test.addTestCase(/*"g_b32",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_b32\";DWORD",                  new PlcDWORD(0xDEADBEEFL));
+        test.addTestCase(/*"g_s32",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_s32\";DINT",                  new PlcDINT(-12345678));
+        test.addTestCase(/*"g_u32",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_u32\";UDINT",                  new PlcUDINT(305419896));
+        // TODO: Getting "INVALID_ADDRESS", as LWORD is not part of 
OpcuaDataType
+//        test.addTestCase(/*"g_b64",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_b64\";LWORD",                  new PlcLWORD(0x0123_4567_89AB_CDEFL));
+        test.addTestCase(/*"g_s64",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_s64\";LINT",                  new PlcLINT(-9223372036854770000L));
+        // TODO: This seems to write different values to the plc.
+//        test.addTestCase(/*"g_u64",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_u64\";ULINT",                  new PlcULINT(new 
BigDecimal("18446744073709551000")));
+        test.addTestCase(/*"g_r32",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_r32\";REAL",                  new PlcREAL(3.14159));
+        test.addTestCase(/*"g_r64",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_r64\";LREAL",                  new PlcLREAL(2.71828182845905));
+        // TODO: Writing of TIME doesn't seem to be supported.
+//        test.addTestCase(/*"g_tim",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_tim\";TIME",             new PlcTIME(2500)); // Is returned as Int32
+        // TODO: IEC 61131-3 date types use 1990-01-01 as epoch, PlcDATE etc. 
use Unix epoch (1970-01-01).
+//        test.addTestCase(/*"g_dat",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_dat\";DATE",             new PlcDATE(LocalDate.of(2025, 11, 12))); 
// Is returned as UInt16
+        // TODO: S7/IEC value is milliseconds since midnight
+//        test.addTestCase(/*"g_timoday",*/       "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_timoday\";TIME_OF_DAY",  new PlcTIME_OF_DAY(LocalTime.of(14, 33, 21, 
250000000))); // Is returned as UInt32
+        // TODO: Getting a class cast exception here
+//        test.addTestCase(/*"g_dattim",*/        "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_dattim\";DATE_AND_TIME",               new 
PlcDATE_AND_LTIME(LocalDateTime.of(2025, 11, 12, 14, 33, 21, 500_000_000)));
+
+        test.addTestCase(/*"g_str",*/           "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_str\";STRING",                  new PlcSTRING("Hello PLC4X"));
+        // TODO: Getting "INVALID_ADDRESS", as WSTRING is not part of 
OpcuaDataType
+//        test.addTestCase(/*"g_wstr",*/          "ns=3;s=\"OPC_UA_DB\".\"OPC 
Data\".\"g_wstr\";WSTRING",                 new PlcWSTRING("Grüße von PLC4X"));
+        if(testArrays) {
+            test.addTestCase(/*"g_arrBool",*/       
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrBool\"", new PlcList(List.of(
+                new PlcBOOL(true), new PlcBOOL(false), new PlcBOOL(true), new 
PlcBOOL(true),
+                new PlcBOOL(false), new PlcBOOL(false), new PlcBOOL(true), new 
PlcBOOL(false))
+            ));
+            test.addTestCase(/*"g_arrByte",*/       
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrByte\"", new PlcList(List.of(
+                new PlcBYTE(0xDE), new PlcBYTE(0xAD), new PlcBYTE(0xBE), new 
PlcBYTE(0xEF),
+                new PlcBYTE(0x12), new PlcBYTE(0x34), new PlcBYTE(0x56), new 
PlcBYTE(0x78))
+            ));
+            test.addTestCase(/*"g_arrInt",*/        
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrInt\"", new PlcList(List.of(
+                new PlcINT(-3), new PlcINT(-1), new PlcINT(0), new PlcINT(1), 
new PlcINT(3))
+            ));
+            test.addTestCase(/*"g_arrUInt",*/       
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrUInt\"", new PlcList(List.of(
+                new PlcUINT(1), new PlcUINT(10), new PlcUINT(100), new 
PlcUINT(1000), new PlcUINT(10000))
+            ));
+            test.addTestCase(/*"g_arrDInt",*/       
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrDInt\"", new PlcList(List.of(
+                new PlcDINT(-1000), new PlcDINT(0), new PlcDINT(1000), new 
PlcDINT(2000000))
+            ));
+            test.addTestCase(/*"g_arrUDInt",*/       
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrUDInt\"", new PlcList(List.of(
+                new PlcUDINT(0), new PlcUDINT(1), new PlcUDINT(0xFFFF), new 
PlcUDINT(0x12345678))
+            ));
+            test.addTestCase(/*"g_arrLReal",*/      
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrLReal\"", new PlcList(List.of(
+                new PlcLREAL(1.5), new PlcLREAL(-2.0), new PlcLREAL(0.125))
+            ));
+            test.addTestCase(/*"g_arrTime",*/       
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrTime\";TIME", new PlcList(List.of(
+                new PlcTIME(Duration.ofMillis(10)), new 
PlcTIME(Duration.ofSeconds(1)), new PlcTIME(Duration.ofSeconds(10)))
+            ));
+            test.addTestCase(/*"g_arrString",*/     
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrString\"", new PlcList(List.of(
+                new PlcSTRING("alpha"), new PlcSTRING("beta"), new 
PlcSTRING("gamma"))
+            ));
+            test.addTestCase(/*"g_arrWString",*/     
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_arrWString\"", new PlcList(List.of(
+                new PlcWSTRING("Äpfel"), new PlcWSTRING("Öl"))
+            ));
+            test.addTestCase(/*"g_matI16_2x3",*/    
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_matI16_2x3\"", new PlcList(List.of(
+                new PlcList(List.of(
+                    new PlcINT(10), new PlcINT(11), new PlcINT(12)
+                )),
+                new PlcList(List.of(
+                    new PlcINT(-10), new PlcINT(-11), new PlcINT(-12)
+                )))
+            ));
+            test.addTestCase(/*"g_matR32_3x2",*/    
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_matR32_3x2\"", new PlcList(List.of(
+                new PlcList(List.of(
+                    new PlcREAL(1.0), new PlcREAL(1.5)
+                )),
+                new PlcList(List.of(
+                    new PlcREAL(2.0), new PlcREAL(2.5)
+                )),
+                new PlcList(List.of(
+                    new PlcREAL(3.0), new PlcREAL(3.5)
+                )))
+            ));
+            test.addTestCase(/*"g_cubeU16_2x2x2",*/ 
"ns=3;s=\"OPC_UA_DB\".\"OPC Data\".\"g_cubeU16_2x2x2\"", new PlcList(List.of(
+                new PlcList(List.of(
+                    new PlcList(List.of(
+                        new PlcUINT(1), new PlcUINT(2)
+                    )),
+                    new PlcList(List.of(
+                        new PlcUINT(3), new PlcUINT(4)
+                    ))
+                )),
+                new PlcList(List.of(
+                    new PlcList(List.of(
+                        new PlcUINT(5), new PlcUINT(6)
+                    )),
+                    new PlcList(List.of(
+                        new PlcUINT(7), new PlcUINT(8)
+                    ))
+                )))
+            ));
+        }
+
+        long start = System.currentTimeMillis();
+        test.run();
+        long end = System.currentTimeMillis();
+        System.out.printf("Finished in %d ms", end - start);
+    }
+
+}
diff --git 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/DefaultPlcValueHandler.java
 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/DefaultPlcValueHandler.java
index 1cd73fdbc6..125cb18c9d 100644
--- 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/DefaultPlcValueHandler.java
+++ 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/DefaultPlcValueHandler.java
@@ -26,6 +26,7 @@ import org.apache.plc4x.java.api.model.PlcTag;
 import org.apache.plc4x.java.api.types.PlcValueType;
 import org.apache.plc4x.java.api.value.PlcValue;
 
+import java.lang.reflect.Array;
 import java.math.BigInteger;
 import java.time.Duration;
 import java.time.LocalDate;
@@ -82,7 +83,7 @@ public class DefaultPlcValueHandler implements 
PlcValueHandler {
     }
 
     private static PlcValue ofElements(PlcValueType type, List<ArrayInfo> 
arrayInfos, Object[] values) {
-        ArrayInfo arrayInfo = arrayInfos.get(0);
+        ArrayInfo arrayInfo = arrayInfos.getFirst();
 
         if(values.length == 1) {
             if(values[0] instanceof Object[]) {
@@ -91,8 +92,7 @@ public class DefaultPlcValueHandler implements 
PlcValueHandler {
                 values = ((Collection<?>) values[0]).toArray();
             } else if(values[0] instanceof PlcList) {
                 values = ((PlcList) values[0]).getList().toArray();
-            } else if(values[0] instanceof PlcRawByteArray) {
-                PlcRawByteArray plcRawByteArray = (PlcRawByteArray) values[0];
+            } else if(values[0] instanceof PlcRawByteArray plcRawByteArray) {
                 if(plcRawByteArray.getRaw().length != arrayInfo.getSize()) {
                     throw new PlcRuntimeException(String.format("Expecting %d 
items, but got %d", arrayInfo.getSize(), plcRawByteArray.getRaw().length));
                 }
@@ -126,6 +126,18 @@ public class DefaultPlcValueHandler implements 
PlcValueHandler {
         if(type == null) {
             return of(value);
         }
+
+        // If this is not a List type, and we're passing in an array or a 
collection with exactly one element,
+        // get that element instead.
+        if (type != PlcValueType.List) {
+            if(value.getClass().isArray() && (Array.getLength(value) == 1)) {
+                value = Array.get(value, 0);
+            }
+            else if((value instanceof Collection<?> col) && (col.size() == 1)) 
{
+                value = col.iterator().next();
+            }
+        }
+
         switch (type) {
             case BOOL:
                 return PlcBOOL.of(value);
diff --git 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/LegacyPlcValueHandler.java
 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/LegacyPlcValueHandler.java
deleted file mode 100644
index 0343bc4434..0000000000
--- 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/LegacyPlcValueHandler.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.spi.values;
-
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
-import org.apache.plc4x.java.api.model.PlcTag;
-import org.apache.plc4x.java.api.value.PlcValue;
-
-import java.math.BigInteger;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.List;
-
-public class LegacyPlcValueHandler implements PlcValueHandler {
-
-    public PlcValue newPlcValue(Object value) {
-        return of(new Object[]{value});
-    }
-
-    public PlcValue newPlcValue(Object[] values) {
-        return of(values);
-    }
-
-    public PlcValue newPlcValue(PlcTag tag, Object value) {
-        return of(tag, new Object[]{value});
-    }
-
-    public PlcValue newPlcValue(PlcTag tag, Object[] values) {
-        return of(tag, values);
-    }
-
-    public static PlcValue of(Object value) {
-        return of(new Object[]{value});
-    }
-
-    public static PlcValue of(List<?> value) {
-        return of(value.toArray());
-    }
-
-    public static PlcValue of(Object[] values) {
-        if (values.length != 1) {
-            PlcList list = new PlcList();
-            for (Object value : values) {
-                list.add(of(new Object[]{value}));
-            }
-            return list;
-        }
-        Object value = values[0];
-        if (value instanceof Boolean) {
-            return PlcBOOL.of(value);
-        }
-        if (value instanceof Byte) {
-            return PlcSINT.of(value);
-        }
-        if (value instanceof byte[]) {
-            return PlcRawByteArray.of(value);
-        }
-        if (value instanceof Short) {
-            return PlcINT.of(value);
-        }
-        if (value instanceof Integer) {
-            return PlcDINT.of(value);
-        }
-        if (value instanceof Long) {
-            return PlcLINT.of(value);
-        }
-        if (value instanceof BigInteger) {
-            return PlcLINT.of(value);
-        }
-        if (value instanceof Float) {
-            return PlcREAL.of(value);
-        }
-        if (value instanceof Double) {
-            return PlcLREAL.of(value);
-        }
-        if (value instanceof Duration) {
-            return new PlcTIME((Duration) value);
-        }
-        if (value instanceof LocalTime) {
-            return new PlcTIME_OF_DAY((LocalTime) value);
-        }
-        if (value instanceof LocalDate) {
-            return new PlcDATE((LocalDate) value);
-        }
-        if (value instanceof LocalDateTime) {
-            return new PlcDATE_AND_TIME((LocalDateTime) value);
-        }
-        if (value instanceof String) {
-            return new PlcSTRING((String) value);
-        }
-        if (value instanceof PlcValue) {
-            return (PlcValue) value;
-        }
-        throw new PlcUnsupportedDataTypeException("Data Type " + 
value.getClass()
-            + " Is not supported");
-    }
-
-
-    public static PlcValue of(PlcTag tag, Object value) {
-        return of(tag, new Object[]{value});
-    }
-
-
-    public static PlcValue of(PlcTag tag, Object[] values) {
-        if (values.length == 1) {
-            Object value = values[0];
-            if(tag.getPlcValueType() == null) {
-                // TODO: This is a hacky shortcut ..
-                if(value instanceof PlcValue) {
-                    return (PlcValue) value;
-                }
-                return new PlcNull();
-            }
-            if (value instanceof PlcValue) {
-                PlcValue plcValue = (PlcValue) value;
-                if (plcValue.getPlcValueType() == tag.getPlcValueType()) {
-                    return (PlcValue) value;
-                } else {
-                    throw new PlcRuntimeException("Expected PlcValue of type " 
+ tag.getPlcValueType().name() + " but got " + 
plcValue.getPlcValueType().name());
-                }
-            }
-            switch (tag.getPlcValueType()) {
-                case BOOL:
-                    return PlcBOOL.of(value);
-                case BYTE:
-                    if(value instanceof Short) {
-                        return new PlcBYTE((short) value);
-                    } else if(value instanceof Integer) {
-                        return new PlcBYTE(((Integer) value).shortValue());
-                    } else if(value instanceof Long) {
-                        return new PlcBYTE(((Long) value).shortValue());
-                    } else if(value instanceof BigInteger) {
-                        return new PlcBYTE(((BigInteger) value).shortValue());
-                    } else if(value instanceof String) {
-                        try {
-                            return new PlcBYTE(Short.valueOf((String) value));
-                        } catch (NumberFormatException e) {
-                            throw new PlcRuntimeException("Value of " + value 
+ " not parseable as Byte");
-                        }
-                    }
-                    throw new PlcRuntimeException("BYTE requires short");
-                case SINT:
-                    return PlcSINT.of(value);
-                case USINT:
-                    return PlcUSINT.of(value);
-                case INT:
-                    return PlcINT.of(value);
-                case UINT:
-                    return PlcUINT.of(value);
-                case WORD:
-                    if(value instanceof Short) {
-                        return new PlcWORD((int) value);
-                    } else if(value instanceof Integer) {
-                        return new PlcWORD((int) value);
-                    } else if(value instanceof Long) {
-                        return new PlcWORD(((Long) value).intValue());
-                    } else if(value instanceof BigInteger) {
-                        return new PlcWORD(((BigInteger) value).intValue());
-                    } else if(value instanceof String) {
-                        try {
-                            return new PlcWORD(Integer.valueOf((String) 
value));
-                        } catch (NumberFormatException e) {
-                            throw new PlcRuntimeException("Value of " + value 
+ " not parseable as Integer");
-                        }
-                    }
-                    throw new PlcRuntimeException("WORD requires int");
-                case DINT:
-                    return PlcDINT.of(value);
-                case UDINT:
-                    return PlcUDINT.of(value);
-                case DWORD:
-                    if(value instanceof Short) {
-                        return new PlcDWORD((long) value);
-                    } else if(value instanceof Integer) {
-                        return new PlcDWORD((long) value);
-                    } else if(value instanceof Long) {
-                        return new PlcDWORD((long) value);
-                    } else if(value instanceof BigInteger) {
-                        return new PlcDWORD(((BigInteger) value).longValue());
-                    } else if(value instanceof String) {
-                        try {
-                            return new PlcDWORD(Long.valueOf((String) value));
-                        } catch (NumberFormatException e) {
-                            throw new PlcRuntimeException("Value of " + value 
+ " not parseable as Long");
-                        }
-                    }
-                    throw new PlcRuntimeException("DWORD requires long");
-                case LINT:
-                    return PlcLINT.of(value);
-                case ULINT:
-                    return PlcULINT.of(value);
-                case LWORD:
-                    if(value instanceof Short) {
-                        return new PlcLWORD(BigInteger.valueOf((long) value));
-                    } else if(value instanceof Integer) {
-                        return new PlcLWORD(BigInteger.valueOf((long) value));
-                    } else if(value instanceof Long) {
-                        return new PlcLWORD(BigInteger.valueOf((long) value));
-                    } else if(value instanceof BigInteger) {
-                        return new PlcLWORD((BigInteger) value);
-                    } else if(value instanceof String) {
-                        try {
-                            return new PlcLWORD(new BigInteger((String) 
value));
-                        } catch (NumberFormatException e) {
-                            throw new PlcRuntimeException("Value of " + value 
+ " not parseable as BigInteger");
-                        }
-                    }
-                    throw new PlcRuntimeException("LWORD requires BigInteger");
-                case REAL:
-                    return PlcREAL.of(value);
-                case LREAL:
-                    return PlcLREAL.of(value);
-                case CHAR:
-                    return PlcCHAR.of(value);
-                case WCHAR:
-                    return PlcWCHAR.of(value);
-                case STRING:
-                    return PlcSTRING.of(value);
-                case WSTRING:
-                    return PlcWSTRING.of(value);
-                case TIME:
-                    return PlcTIME.of(value);
-                case DATE:
-                    return PlcDATE.of(value);
-                case TIME_OF_DAY:
-                    return PlcTIME_OF_DAY.of(value);
-                case DATE_AND_TIME:
-                    return PlcDATE_AND_TIME.of(value);
-                default:
-                    return customDataType(new Object[]{value});
-            }
-        } else {
-            PlcList list = new PlcList();
-            for (Object value : values) {
-                list.add(of(tag, new Object[]{value}));
-            }
-            return list;
-        }
-    }
-
-    public static PlcValue customDataType(Object[] values) {
-        return of(values);
-    }
-}


Reply via email to