You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/04/21 14:10:23 UTC

[plc4x] branch develop updated (c7e332f -> c0ffbf1)

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

sruehl pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git.


    from c7e332f  Added a missing Apache header
     new f19f42b  plc4go: enable validation on ReadBufferJsonBased by default
     new c32d202  plc4go: fixed bug where strings could overwrite their encoding in json
     new dabe0cf  plc4j: implemented json based read and write buffers.
     new c0ffbf1  plc4j: json based read and write buffers. Are now compatible to plc4go

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../resources/templates/java/io-template.java.ftlh |  24 +-
 .../plc4go/spi/utils/ReadBufferJsonBased.go        |  50 ++-
 .../plc4go/spi/utils/WriteBufferJsonBased.go       |   2 +-
 plc4j/drivers/s7/pom.xml                           |  11 +-
 plc4j/drivers/s7/src/test/java/S7IoTest.java       | 151 ++++++++-
 plc4j/spi/pom.xml                                  |   8 +
 .../plc4x/java/spi/generation/BufferCommons.java   |  59 ++++
 .../plc4x/java/spi/generation/ReadBuffer.java      |  34 +-
 .../java/spi/generation/ReadBufferByteBased.java   |  34 +-
 .../java/spi/generation/ReadBufferJsonBased.java   | 377 +++++++++++++++++++++
 .../java/spi/generation/ReadBufferXmlBased.java    |  78 ++---
 .../plc4x/java/spi/generation/WithReaderArgs.java} |   9 +-
 .../java/spi/generation/WithReaderWriterArgs.java} |  21 +-
 .../plc4x/java/spi/generation/WithWriterArgs.java} |   9 +-
 .../plc4x/java/spi/generation/WriteBuffer.java     |  42 +--
 .../java/spi/generation/WriteBufferByteBased.java  | 104 +++---
 .../java/spi/generation/WriteBufferJsonBased.java  | 282 +++++++++++++++
 .../java/spi/generation/WriteBufferXmlBased.java   |  80 +++--
 18 files changed, 1114 insertions(+), 261 deletions(-)
 create mode 100644 plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
 create mode 100644 plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java
 copy plc4j/{protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/package-info.java => spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderArgs.java} (88%)
 copy plc4j/{drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubscriptionHandleTest.java => spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderWriterArgs.java} (69%)
 copy plc4j/{protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/package-info.java => spi/src/main/java/org/apache/plc4x/java/spi/generation/WithWriterArgs.java} (88%)
 create mode 100644 plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java

[plc4x] 02/04: plc4go: fixed bug where strings could overwrite their encoding in json

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit c32d2024733d96e51075bc351bd55194aabf0340
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Apr 21 13:38:02 2021 +0200

    plc4go: fixed bug where strings could overwrite their encoding in json
---
 plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go
index f902937..c463037 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go
@@ -150,7 +150,7 @@ func (j *jsonWriteBuffer) WriteBigFloat(logicalName string, bitLength uint8, val
 
 func (j *jsonWriteBuffer) WriteString(logicalName string, bitLength uint8, encoding string, value string, writerArgs ...WithWriterArgs) error {
 	attr := j.generateAttr(logicalName, rwStringKey, bitLength, writerArgs...)
-	attr[fmt.Sprintf("__plc4x_%s", rwEncodingKey)] = encoding
+	attr[fmt.Sprintf("%s__plc4x_%s", logicalName, rwEncodingKey)] = encoding
 	return j.encodeNode(logicalName, value, attr)
 }
 

[plc4x] 04/04: plc4j: json based read and write buffers. Are now compatible to plc4go

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit c0ffbf1e86838e90a657d6aa07db1b41198f80b7
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Apr 21 16:09:28 2021 +0200

    plc4j: json based read and write buffers. Are now compatible to plc4go
---
 .../resources/templates/java/io-template.java.ftlh |  24 +-
 plc4j/drivers/s7/pom.xml                           |  11 +-
 plc4j/drivers/s7/src/test/java/S7IoTest.java       |  24 +-
 .../plc4x/java/spi/generation/BufferCommons.java   |  37 ++-
 .../plc4x/java/spi/generation/ReadBuffer.java      |  34 +--
 .../java/spi/generation/ReadBufferByteBased.java   |  34 +--
 .../java/spi/generation/ReadBufferJsonBased.java   |  73 +++---
 .../java/spi/generation/ReadBufferXmlBased.java    |  38 +--
 .../{BufferCommons.java => WithReaderArgs.java}    |  19 +-
 ...ufferCommons.java => WithReaderWriterArgs.java} |  24 +-
 .../{BufferCommons.java => WithWriterArgs.java}    |  19 +-
 .../plc4x/java/spi/generation/WriteBuffer.java     |  42 ++--
 .../java/spi/generation/WriteBufferByteBased.java  | 104 ++++----
 .../java/spi/generation/WriteBufferJsonBased.java  | 266 +++++++++++----------
 .../java/spi/generation/WriteBufferXmlBased.java   |  34 +--
 15 files changed, 387 insertions(+), 396 deletions(-)

diff --git a/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh b/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
index 2eff639..341503c 100644
--- a/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -155,7 +155,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#assign arrayField = field>
 
         // Array field (${arrayField.name})
-        io.pullContext("${arrayField.name}");
+        io.pullContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         <#-- Only update curPos if the length expression uses it -->
         <#if arrayField.loopExpression.contains("curPos")>
         curPos = io.getPos() - startPos;
@@ -218,7 +218,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]);
             </#if>
         </#if>
-        io.closeContext("${arrayField.name}");
+        io.closeContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         <#break>
     <#case "checksum">
         <#assign checksumField = field>
@@ -281,7 +281,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
     <#case "manualArray">
         <#assign manualArrayField = field>
 
-        io.pullContext("${manualArrayField.name}");
+        io.pullContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         // Manual Array Field (${manualArrayField.name})
         <#-- Only update curPos if the length expression uses it -->
         <#if manualArrayField.loopExpression.contains("curPos")>
@@ -337,7 +337,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = _${manualArrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}[0]);
             </#if>
         </#if>
-        io.closeContext("${manualArrayField.name}");
+        io.closeContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         <#break>
     <#case "manual">
         <#assign manualField = field>
@@ -367,13 +367,13 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 
         // Padding Field (padding)
         {
-            io.pullContext("padding");
+            io.pullContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
             int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)});
             while ((io.hasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding-- > 0)) {
                 // Just read the padding data and ignore it
                 ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)};
             }
-            io.closeContext("padding");
+            io.closeContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "reserved">
@@ -456,7 +456,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 
         // Array Field (${arrayField.name})
         if(_value.get${arrayField.name?cap_first}() != null) {
-            io.pushContext("${arrayField.name}");
+            io.pushContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
             int itemCount = (int) _value.get${arrayField.name?cap_first}().length;
             int curItem = 0;
             for(${helper.getLanguageTypeNameForField(field)} element : _value.get${arrayField.name?cap_first}()) {
@@ -470,7 +470,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
                 </#if>
                 curItem++;
             }
-            io.popContext("${arrayField.name}");
+            io.popContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "checksum">
@@ -540,11 +540,11 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 
         // Manual Array Field (${manualArrayField.name})
         if(_value.get${manualArrayField.name?cap_first}() != null) {
-            io.pushContext("${manualArrayField.name}");
+            io.pushContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
             for(${helper.getLanguageTypeNameForField(field)} element : _value.get${manualArrayField.name?cap_first}()) {
                 ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, type.parserArguments)};
             }
-            io.pushContext("${manualArrayField.name}");
+            io.pushContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "manual">
@@ -579,13 +579,13 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 
         // Padding Field (padding)
         {
-            io.pushContext("padding");
+            io.pushContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
             int _timesPadding = (int) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)});
             while (_timesPadding-- > 0) {
                 ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, type.parserArguments)});
                 ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", field)};
             }
-            io.popContext("padding");
+            io.popContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "reserved">
diff --git a/plc4j/drivers/s7/pom.xml b/plc4j/drivers/s7/pom.xml
index bb539b6..c3f02e8 100644
--- a/plc4j/drivers/s7/pom.xml
+++ b/plc4j/drivers/s7/pom.xml
@@ -17,7 +17,8 @@
   specific language governing permissions and limitations
   under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
@@ -89,7 +90,8 @@
           <instructions>
             <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
             <Bundle-Activator>org.apache.plc4x.java.osgi.DriverActivator</Bundle-Activator>
-            <Export-Service>org.apache.plc4x.java.api.PlcDriver,org.apache.plc4x.java.s7.readwrite.S7Driver</Export-Service>
+            <Export-Service>org.apache.plc4x.java.api.PlcDriver,org.apache.plc4x.java.s7.readwrite.S7Driver
+            </Export-Service>
             <Import-Package>
               com.fasterxml.jackson.annotation;resolution:=optional,
               *
@@ -159,6 +161,11 @@
       <version>0.9.0-SNAPSHOT</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <scope>test</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.plc4x</groupId>
diff --git a/plc4j/drivers/s7/src/test/java/S7IoTest.java b/plc4j/drivers/s7/src/test/java/S7IoTest.java
index 1d319d8..332db1c 100644
--- a/plc4j/drivers/s7/src/test/java/S7IoTest.java
+++ b/plc4j/drivers/s7/src/test/java/S7IoTest.java
@@ -17,6 +17,7 @@
  under the License.
  */
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.plc4x.java.s7.readwrite.*;
 import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
 import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize;
@@ -35,9 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class S7IoTest {
 
-    // TODO: delete when done
-    boolean isJsonRenderingDone = false;
-
     @Test
     void TestS7MessageBytes() throws Exception {
         String wantXml =
@@ -105,7 +103,7 @@ public class S7IoTest {
                 "    </COTPPacket>\n" +
                 "  </payload>\n" +
                 "</TPKTPacket>\n";
-        String wantJson ="{\n" +
+        String wantJson = "{\n" +
             "  \"TPKTPacket\": {\n" +
             "    \"len\": 29,\n" +
             "    \"len__plc4x_bitLength\": 16,\n" +
@@ -146,7 +144,9 @@ public class S7IoTest {
             "                  \"S7VarPayloadDataItem\": {\n" +
             "                    \"data\": [\n" +
             "                      {\n" +
-            "                        \"value\": 1\n" +
+            "                        \"value\": 1,\n" +
+            "                        \"value__plc4x_bitLength\": 8,\n" +
+            "                        \"value__plc4x_dataType\": \"int\"\n" +
             "                      }\n" +
             "                    ],\n" +
             "                    \"dataLength\": 1,\n" +
@@ -156,14 +156,12 @@ public class S7IoTest {
             "                    \"returnCode\": {\n" +
             "                      \"DataTransportErrorCode\": 255,\n" +
             "                      \"DataTransportErrorCode__plc4x_bitLength\": 8,\n" +
-            "                      \"DataTransportErrorCode__plc4x_dataType\": \"uint\",\n" +
-            "                      \"DataTransportErrorCode__plc4x_stringRepresentation\": \"OK\"\n" +
+            "                      \"DataTransportErrorCode__plc4x_dataType\": \"uint\"\n" +
             "                    },\n" +
             "                    \"transportSize\": {\n" +
             "                      \"DataTransportSize\": 3,\n" +
             "                      \"DataTransportSize__plc4x_bitLength\": 8,\n" +
-            "                      \"DataTransportSize__plc4x_dataType\": \"uint\",\n" +
-            "                      \"DataTransportSize__plc4x_stringRepresentation\": \"BIT\"\n" +
+            "                      \"DataTransportSize__plc4x_dataType\": \"uint\"\n" +
             "                    }\n" +
             "                  }\n" +
             "                }\n" +
@@ -199,8 +197,7 @@ public class S7IoTest {
             "                \"tpduSize\": {\n" +
             "                  \"COTPTpduSize\": 12,\n" +
             "                  \"COTPTpduSize__plc4x_bitLength\": 8,\n" +
-            "                  \"COTPTpduSize__plc4x_dataType\": \"int\",\n" +
-            "                  \"COTPTpduSize__plc4x_stringRepresentation\": \"SIZE_4096\"\n" +
+            "                  \"COTPTpduSize__plc4x_dataType\": \"int\"\n" +
             "                }\n" +
             "              },\n" +
             "              \"parameterLength\": 1,\n" +
@@ -264,9 +261,8 @@ public class S7IoTest {
             WriteBufferJsonBased writeBufferJsonBased = new WriteBufferJsonBased();
             TPKTPacketIO.staticSerialize(writeBufferJsonBased, tpktPacket);
             String gotJson = writeBufferJsonBased.getJsonString();
-            if (isJsonRenderingDone) {
-                assertEquals(wantJson, gotJson);
-            }
+            ObjectMapper objectMapper = new ObjectMapper();
+            assertEquals(objectMapper.readTree(wantJson),objectMapper.readTree(gotJson));
             ReadBufferJsonBased readBufferXmlBased = new ReadBufferJsonBased(new ByteArrayInputStream(gotJson.getBytes()));
             TPKTPacket reReadTpktPacket = TPKTPacketIO.staticParse(readBufferXmlBased);
             assertThat(reReadTpktPacket).usingRecursiveComparison().isEqualTo(tpktPacket);
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
index c3d01d9..6cec58c 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
@@ -19,17 +19,19 @@
 
 package org.apache.plc4x.java.spi.generation;
 
+import java.util.stream.Stream;
+
 public interface BufferCommons {
-    String rwDataTypeKey             = "dataType";
-    String rwBitLengthKey            = "bitLength";
+    String rwDataTypeKey = "dataType";
+    String rwBitLengthKey = "bitLength";
     String rwStringRepresentationKey = "stringRepresentation";
-    String rwBitKey                  = "bit";
-    String rwUintKey                 = "uint";
-    String rwIntKey                  = "int";
-    String rwFloatKey                = "float";
-    String rwStringKey               = "string";
-    String rwEncodingKey             = "encoding";
-    String rwIsListKey               = "isList";
+    String rwBitKey = "bit";
+    String rwUintKey = "uint";
+    String rwIntKey = "int";
+    String rwFloatKey = "float";
+    String rwStringKey = "string";
+    String rwEncodingKey = "encoding";
+    String rwIsListKey = "isList";
 
     default String sanitizeLogicalName(String logicalName) {
         if (logicalName.equals("")) {
@@ -37,4 +39,21 @@ public interface BufferCommons {
         }
         return logicalName;
     }
+
+    default boolean isToBeRenderedAsList(WithReaderArgs... readerArgs) {
+        return isToBeRenderedAsList(Stream.of(readerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+    }
+
+    default boolean isToBeRenderedAsList(WithWriterArgs... writerArgs) {
+        return isToBeRenderedAsList(Stream.of(writerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+    }
+
+    default boolean isToBeRenderedAsList(WithReaderWriterArgs... readerWriterArgs) {
+        for (WithReaderWriterArgs arg : readerWriterArgs) {
+            if (arg instanceof withRenderAsList) {
+                return ((withRenderAsList) arg).renderAsList();
+            }
+        }
+        return false;
+    }
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index 1c8f329..13f3991 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -27,98 +27,98 @@ public interface ReadBuffer {
 
     boolean hasMore(int numBits);
 
-    void pullContext(String logicalName);
+    void pullContext(String logicalName, WithReaderArgs... readerArgs);
 
-    boolean readBit(String logicalName) throws ParseException;
+    boolean readBit(String logicalName, WithReaderArgs... readerArgs) throws ParseException;
 
     default boolean readBit() throws ParseException {
         return readBit("");
     }
 
-    byte readUnsignedByte(String logicalName, int bitLength) throws ParseException;
+    byte readUnsignedByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default byte readUnsignedByte(int bitLength) throws ParseException {
         return readUnsignedByte("", bitLength);
     }
 
-    short readUnsignedShort(String logicalName, int bitLength) throws ParseException;
+    short readUnsignedShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default short readUnsignedShort(int bitLength) throws ParseException {
         return readUnsignedShort("", bitLength);
     }
 
-    int readUnsignedInt(String logicalName, int bitLength) throws ParseException;
+    int readUnsignedInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default int readUnsignedInt(int bitLength) throws ParseException {
         return readUnsignedInt("", bitLength);
     }
 
-    long readUnsignedLong(String logicalName, int bitLength) throws ParseException;
+    long readUnsignedLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default long readUnsignedLong(int bitLength) throws ParseException {
         return readUnsignedLong("", bitLength);
     }
 
-    BigInteger readUnsignedBigInteger(String logicalName, int bitLength) throws ParseException;
+    BigInteger readUnsignedBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default BigInteger readUnsignedBigInteger(int bitLength) throws ParseException {
         return readUnsignedBigInteger("", bitLength);
     }
 
-    byte readByte(String logicalName, int bitLength) throws ParseException;
+    byte readByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default byte readByte(int bitLength) throws ParseException {
         return readByte("", bitLength);
     }
 
-    short readShort(String logicalName, int bitLength) throws ParseException;
+    short readShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default short readShort(int bitLength) throws ParseException {
         return readShort("", bitLength);
     }
 
-    int readInt(String logicalName, int bitLength) throws ParseException;
+    int readInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default int readInt(int bitLength) throws ParseException {
         return readInt("", bitLength);
     }
 
-    long readLong(String logicalName, int bitLength) throws ParseException;
+    long readLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default long readLong(int bitLength) throws ParseException {
         return readLong("", bitLength);
     }
 
-    BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException;
+    BigInteger readBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default BigInteger readBigInteger(int bitLength) throws ParseException {
         return readBigInteger("", bitLength);
     }
 
-    float readFloat(String logicalName, int bitLength) throws ParseException;
+    float readFloat(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default float readFloat(int bitLength) throws ParseException {
         return readFloat("", bitLength);
     }
 
-    double readDouble(String logicalName, int bitLength) throws ParseException;
+    double readDouble(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default double readDouble(int bitLength) throws ParseException {
         return readDouble("", bitLength);
     }
 
-    BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException;
+    BigDecimal readBigDecimal(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default BigDecimal readBigDecimal(int bitLength) throws ParseException {
         return readBigDecimal("", bitLength);
     }
 
-    String readString(String logicalName, int bitLength, String encoding);
+    String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs);
 
     default String readString(int bitLength, String encoding) {
         return readString("", bitLength,encoding);
     }
 
 
-    void closeContext(String logicalName);
+    void closeContext(String logicalName, WithReaderArgs... readerArgs);
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
index 5e35310..1d4f4c5 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
@@ -83,11 +83,11 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public void pullContext(String logicalName) {
+    public void pullContext(String logicalName, WithReaderArgs... readerArgs) {
     }
 
     @Override
-    public boolean readBit(String logicalName) throws ParseException {
+    public boolean readBit(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         try {
             return bi.readBoolean();
         } catch (IOException e) {
@@ -96,7 +96,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public byte readUnsignedByte(String logicalName, int bitLength) throws ParseException {
+    public byte readUnsignedByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("unsigned byte must contain at least 1 bit");
         }
@@ -111,7 +111,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public short readUnsignedShort(String logicalName, int bitLength) throws ParseException {
+    public short readUnsignedShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("unsigned short must contain at least 1 bit");
         }
@@ -127,7 +127,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public int readUnsignedInt(String logicalName, int bitLength) throws ParseException {
+    public int readUnsignedInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("unsigned int must contain at least 1 bit");
         }
@@ -146,7 +146,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public long readUnsignedLong(String logicalName, int bitLength) throws ParseException {
+    public long readUnsignedLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("unsigned long must contain at least 1 bit");
         }
@@ -165,7 +165,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength) throws ParseException {
+    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         //Support specific case where value less than 64 bits and big endian.
         if (bitLength <= 0) {
             throw new ParseException("unsigned long must contain at least 1 bit");
@@ -191,7 +191,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public byte readByte(String logicalName, int bitLength) throws ParseException {
+    public byte readByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("byte must contain at least 1 bit");
         }
@@ -206,7 +206,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public short readShort(String logicalName, int bitLength) throws ParseException {
+    public short readShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("short must contain at least 1 bit");
         }
@@ -224,7 +224,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public int readInt(String logicalName, int bitLength) throws ParseException {
+    public int readInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("int must contain at least 1 bit");
         }
@@ -242,7 +242,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public long readLong(String logicalName, int bitLength) throws ParseException {
+    public long readLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength <= 0) {
             throw new ParseException("long must contain at least 1 bit");
         }
@@ -260,12 +260,12 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException {
+    public BigInteger readBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         throw new UnsupportedOperationException("not implemented yet");
     }
 
     @Override
-    public float readFloat(String logicalName, int bitLength) throws ParseException {
+    public float readFloat(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         try {
             if (bitLength == 16) {
                 // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
@@ -301,7 +301,7 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public double readDouble(String logicalName, int bitLength) throws ParseException {
+    public double readDouble(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         if(bitLength == 64) {
             long longValue = readLong(logicalName,64);
             return Double.longBitsToDouble(longValue);
@@ -311,12 +311,12 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException {
+    public BigDecimal readBigDecimal(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         throw new UnsupportedOperationException("not implemented yet");
     }
 
     @Override
-    public String readString(String logicalName, int bitLength, String encoding) {
+    public String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs) {
         byte[] strBytes = new byte[bitLength / 8];
         for (int i = 0; (i < (bitLength / 8)) && hasMore(8); i++) {
             try {
@@ -331,7 +331,7 @@ public class ReadBufferByteBased implements ReadBuffer {
 
 
     @Override
-    public void closeContext(String logicalName) {
+    public void closeContext(String logicalName, WithReaderArgs... readerArgs) {
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java
index 46c4736..cd8ea37 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java
@@ -26,9 +26,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Stack;
+import java.util.*;
 
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class ReadBufferJsonBased implements ReadBuffer {
@@ -64,7 +62,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public void pullContext(String logicalName) {
+    public void pullContext(String logicalName, WithReaderArgs... readerArgs) {
         logicalName = sanitizeLogicalName(logicalName);
         if (stack.empty()) {
             if (!(rootElement instanceof Map)) {
@@ -78,22 +76,24 @@ public class ReadBufferJsonBased implements ReadBuffer {
             return;
         }
         Object peek = stack.peek();
-        if (peek.getClass().isArray()) {
-            Object[] contextList = (Object[]) stack.pop();
-            Object context = contextList[0];
-            if (contextList.length < 2) {
-                stack.push(new Object[]{});
+        if (peek instanceof List) {
+            List contextList = (List) stack.pop();
+            Object context = contextList.get(0);
+            if (contextList.size() < 2) {
+                stack.push(Collections.emptyList());
             } else {
-                stack.push(Arrays.copyOfRange(contextList, 1, contextList.length - 1));
+                contextList.remove(0);
+                stack.push(contextList);
             }
             Object subContext = ((Map) context).get(logicalName);
             if (subContext == null) {
                 throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
             }
             stack.push(subContext);
+            return;
         }
         if (!(peek instanceof Map)) {
-            throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
+            throw new PlcRuntimeException("Invalid parser state");
         }
         Map map = (Map) peek;
         Object context = map.get(logicalName);
@@ -104,7 +104,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public boolean readBit(String logicalName) throws ParseException {
+    public boolean readBit(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(1);
         Map element = getElement(logicalName);
@@ -117,7 +117,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public byte readUnsignedByte(String logicalName, int bitLength) throws ParseException {
+    public byte readUnsignedByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -130,7 +130,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public short readUnsignedShort(String logicalName, int bitLength) throws ParseException {
+    public short readUnsignedShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -143,7 +143,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public int readUnsignedInt(String logicalName, int bitLength) throws ParseException {
+    public int readUnsignedInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -156,7 +156,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public long readUnsignedLong(String logicalName, int bitLength) throws ParseException {
+    public long readUnsignedLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -169,7 +169,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength) throws ParseException {
+    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -182,7 +182,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public byte readByte(String logicalName, int bitLength) throws ParseException {
+    public byte readByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -195,7 +195,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public short readShort(String logicalName, int bitLength) throws ParseException {
+    public short readShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -208,7 +208,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public int readInt(String logicalName, int bitLength) throws ParseException {
+    public int readInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -221,7 +221,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public long readLong(String logicalName, int bitLength) throws ParseException {
+    public long readLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -234,7 +234,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException {
+    public BigInteger readBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -247,7 +247,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public float readFloat(String logicalName, int bitLength) throws ParseException {
+    public float readFloat(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -260,7 +260,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public double readDouble(String logicalName, int bitLength) throws ParseException {
+    public double readDouble(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -273,7 +273,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException {
+    public BigDecimal readBigDecimal(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -286,7 +286,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public String readString(String logicalName, int bitLength, String encoding) {
+    public String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs) {
         logicalName = sanitizeLogicalName(logicalName);
         move(bitLength);
         Map element = getElement(logicalName);
@@ -299,7 +299,7 @@ public class ReadBufferJsonBased implements ReadBuffer {
     }
 
     @Override
-    public void closeContext(String logicalName) {
+    public void closeContext(String logicalName, WithReaderArgs... readerArgs) {
         logicalName = sanitizeLogicalName(logicalName);
         if (stack.empty()) {
             throw new PlcRuntimeException(String.format("Required context close %s not found in %s", logicalName, rootElement));
@@ -310,9 +310,12 @@ public class ReadBufferJsonBased implements ReadBuffer {
             return;
         }
         Object peek =stack.peek();
-        if (peek.getClass().isArray()) {
+        if (peek instanceof List) {
             return;
         }
+        if (!(peek instanceof Map)) {
+            throw new PlcRuntimeException("Invalid parser state");
+        }
         Map map = (Map) peek;
         if (map.get(logicalName)==null) {
             throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
@@ -325,14 +328,14 @@ public class ReadBufferJsonBased implements ReadBuffer {
         logicalName = sanitizeLogicalName(logicalName);
         Object peek = stack.peek();
         Map element;
-        if (peek.getClass().isArray()) {
-            Object pop = stack.pop();
-            Object[] elementList = (Object[]) pop;
-            element = (Map) elementList[0];
-            if (elementList.length < 2) {
-                stack.push(new Object[]{});
+        if (peek instanceof List) {
+            List elementList = (List)stack.pop();
+            element = (Map) elementList.get(0);
+            if (elementList.size() < 2) {
+                stack.push(Collections.emptyList());
             } else {
-                stack.push(Arrays.copyOfRange(elementList, 1, elementList.length - 1));
+                elementList.remove(0);
+                stack.push(elementList);
             }
             return element;
         } else if (peek instanceof Map) {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
index a63d5ab..8139677 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
@@ -56,7 +56,7 @@ public class ReadBufferXmlBased implements ReadBuffer, BufferCommons {
     }
 
     @Override
-    public void pullContext(String logicalName) {
+    public void pullContext(String logicalName, WithReaderArgs... readerArgs) {
         StartElement startElement = travelToNextStartElement();
         String elementName = startElement.getName().getLocalPart();
         if (!elementName.equals(logicalName)) {
@@ -65,98 +65,98 @@ public class ReadBufferXmlBased implements ReadBuffer, BufferCommons {
     }
 
     @Override
-    public boolean readBit(String logicalName) throws ParseException {
+    public boolean readBit(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         String bit = decode(logicalName, rwBitKey, 1);
         move(1);
         return bit.equals("1");
     }
 
     @Override
-    public byte readUnsignedByte(String logicalName, int bitLength) throws ParseException {
+    public byte readUnsignedByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Byte.parseByte(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
-    public short readUnsignedShort(String logicalName, int bitLength) throws ParseException {
+    public short readUnsignedShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Short.parseShort(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
-    public int readUnsignedInt(String logicalName, int bitLength) throws ParseException {
+    public int readUnsignedInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Integer.parseInt(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
-    public long readUnsignedLong(String logicalName, int bitLength) throws ParseException {
+    public long readUnsignedLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Long.parseLong(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
-    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength) throws ParseException {
+    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         throw new PlcRuntimeException("not implemented yet");
     }
 
     @Override
-    public byte readByte(String logicalName, int bitLength) throws ParseException {
+    public byte readByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Byte.parseByte(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
-    public short readShort(String logicalName, int bitLength) throws ParseException {
+    public short readShort(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Short.parseShort(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
-    public int readInt(String logicalName, int bitLength) throws ParseException {
+    public int readInt(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Integer.parseInt(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
-    public long readLong(String logicalName, int bitLength) throws ParseException {
+    public long readLong(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Long.parseLong(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
-    public BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException {
+    public BigInteger readBigInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return new BigInteger(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
-    public float readFloat(String logicalName, int bitLength) throws ParseException {
+    public float readFloat(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Float.parseFloat(decode(logicalName, rwFloatKey, bitLength));
     }
 
     @Override
-    public double readDouble(String logicalName, int bitLength) throws ParseException {
+    public double readDouble(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return Double.parseDouble(decode(logicalName, rwFloatKey, bitLength));
     }
 
     @Override
-    public BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException {
+    public BigDecimal readBigDecimal(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
         move(bitLength);
         return new BigDecimal(decode(logicalName, rwFloatKey, bitLength));
     }
 
     @Override
-    public String readString(String logicalName, int bitLength, String encoding) {
+    public String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs) {
         move(bitLength);
         return decode(logicalName, rwStringKey, bitLength);
     }
 
     @Override
-    public void closeContext(String logicalName) {
+    public void closeContext(String logicalName, WithReaderArgs... readerArgs) {
         EndElement endElement = travelToNextEndElement();
         if (!endElement.getName().getLocalPart().equals(logicalName)) {
             throw new PlcRuntimeException(String.format("Unexpected End element '%s'. Expected '%s'", endElement.getName().getLocalPart(), logicalName));
@@ -247,10 +247,10 @@ public class ReadBufferXmlBased implements ReadBuffer, BufferCommons {
             }
         }
         if (!dataTypeValidated) {
-            throw new PlcRuntimeException(String.format("required attribute %s missing",rwDataTypeKey));
+            throw new PlcRuntimeException(String.format("required attribute %s missing", rwDataTypeKey));
         }
         if (!bitLengthValidate) {
-            throw new PlcRuntimeException(String.format("required attribute %s missing",rwBitLengthKey));
+            throw new PlcRuntimeException(String.format("required attribute %s missing", rwBitLengthKey));
         }
         return true;
     }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderArgs.java
similarity index 53%
copy from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
copy to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderArgs.java
index c3d01d9..9286799 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderArgs.java
@@ -19,22 +19,5 @@
 
 package org.apache.plc4x.java.spi.generation;
 
-public interface BufferCommons {
-    String rwDataTypeKey             = "dataType";
-    String rwBitLengthKey            = "bitLength";
-    String rwStringRepresentationKey = "stringRepresentation";
-    String rwBitKey                  = "bit";
-    String rwUintKey                 = "uint";
-    String rwIntKey                  = "int";
-    String rwFloatKey                = "float";
-    String rwStringKey               = "string";
-    String rwEncodingKey             = "encoding";
-    String rwIsListKey               = "isList";
-
-    default String sanitizeLogicalName(String logicalName) {
-        if (logicalName.equals("")) {
-            return "value";
-        }
-        return logicalName;
-    }
+public interface WithReaderArgs {
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderWriterArgs.java
similarity index 54%
copy from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
copy to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderWriterArgs.java
index c3d01d9..0e6f241 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithReaderWriterArgs.java
@@ -19,22 +19,12 @@
 
 package org.apache.plc4x.java.spi.generation;
 
-public interface BufferCommons {
-    String rwDataTypeKey             = "dataType";
-    String rwBitLengthKey            = "bitLength";
-    String rwStringRepresentationKey = "stringRepresentation";
-    String rwBitKey                  = "bit";
-    String rwUintKey                 = "uint";
-    String rwIntKey                  = "int";
-    String rwFloatKey                = "float";
-    String rwStringKey               = "string";
-    String rwEncodingKey             = "encoding";
-    String rwIsListKey               = "isList";
-
-    default String sanitizeLogicalName(String logicalName) {
-        if (logicalName.equals("")) {
-            return "value";
-        }
-        return logicalName;
+public interface WithReaderWriterArgs extends WithReaderArgs, WithWriterArgs {
+    static WithReaderWriterArgs WithRenderAsList(boolean renderAsList) {
+        return (withRenderAsList) () -> renderAsList;
     }
 }
+
+interface withRenderAsList extends WithReaderWriterArgs {
+    boolean renderAsList();
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithWriterArgs.java
similarity index 53%
copy from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
copy to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithWriterArgs.java
index c3d01d9..82f03e4 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WithWriterArgs.java
@@ -19,22 +19,5 @@
 
 package org.apache.plc4x.java.spi.generation;
 
-public interface BufferCommons {
-    String rwDataTypeKey             = "dataType";
-    String rwBitLengthKey            = "bitLength";
-    String rwStringRepresentationKey = "stringRepresentation";
-    String rwBitKey                  = "bit";
-    String rwUintKey                 = "uint";
-    String rwIntKey                  = "int";
-    String rwFloatKey                = "float";
-    String rwStringKey               = "string";
-    String rwEncodingKey             = "encoding";
-    String rwIsListKey               = "isList";
-
-    default String sanitizeLogicalName(String logicalName) {
-        if (logicalName.equals("")) {
-            return "value";
-        }
-        return logicalName;
-    }
+public interface WithWriterArgs {
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
index 23cd4b4..25b910b 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
@@ -26,97 +26,97 @@ public interface WriteBuffer {
     // TODO: check if this is really needed or if this is just an artifact
     int getPos();
 
-    void pushContext(String logicalName);
+    void pushContext(String logicalName, WithWriterArgs... writerArgs);
 
-    void writeBit(String logicalName, boolean value) throws ParseException;
+    void writeBit(String logicalName, boolean value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeBit(boolean value) throws ParseException {
         writeBit("", value);
     }
 
-    void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException;
+    void writeUnsignedByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeUnsignedByte(int bitLength, byte value) throws ParseException {
-        writeUnsignedByte("", bitLength,value);
+        writeUnsignedByte("", bitLength, value);
     }
 
-    void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException;
+    void writeUnsignedShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeUnsignedShort(int bitLength, short value) throws ParseException {
         writeUnsignedShort("", bitLength, value);
     }
 
-    void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException;
+    void writeUnsignedInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeUnsignedInt(int bitLength, int value) throws ParseException {
         writeUnsignedInt("", bitLength, value);
     }
 
-    void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException;
+    void writeUnsignedLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeUnsignedLong(int bitLength, long value) throws ParseException {
         writeUnsignedLong("", bitLength, value);
     }
 
-    void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException;
+    void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeUnsignedBigInteger(int bitLength, BigInteger value) throws ParseException {
         writeUnsignedBigInteger("", bitLength, value);
     }
 
-    void writeByte(String logicalName, int bitLength, byte value) throws ParseException;
+    void writeByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeByte(int bitLength, byte value) throws ParseException {
         writeByte("", bitLength, value);
     }
 
-    void writeShort(String logicalName, int bitLength, short value) throws ParseException;
+    void writeShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeShort(int bitLength, short value) throws ParseException {
         writeShort("", bitLength, value);
     }
 
-    void writeInt(String logicalName, int bitLength, int value) throws ParseException;
+    void writeInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeInt(int bitLength, int value) throws ParseException {
         writeInt("", bitLength, value);
     }
 
-    void writeLong(String logicalName, int bitLength, long value) throws ParseException;
+    void writeLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeLong(int bitLength, long value) throws ParseException {
         writeLong("", bitLength, value);
     }
 
-    void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException;
+    void writeBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeBigInteger(int bitLength, BigInteger value) throws ParseException {
         writeBigInteger("", bitLength, value);
     }
 
-    void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException;
+    void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeFloat(float value, int bitsExponent, int bitsMantissa) throws ParseException {
-        writeFloat("", value, bitsExponent,bitsMantissa);
+        writeFloat("", value, bitsExponent, bitsMantissa);
     }
 
-    void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException;
+    void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeDouble(double value, int bitsExponent, int bitsMantissa) throws ParseException {
-        writeDouble("", value,bitsExponent,bitsMantissa);
+        writeDouble("", value, bitsExponent, bitsMantissa);
     }
 
-    void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException;
+    void writeBigDecimal(String logicalName, int bitLength, BigDecimal value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeBigDecimal(int bitLength, BigDecimal value) throws ParseException {
         writeBigDecimal("", bitLength, value);
     }
 
-    void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException;
+    void writeString(String logicalName, int bitLength, String encoding, String value, WithWriterArgs... writerArgs) throws ParseException;
 
     default void writeString(int bitLength, String encoding, String value) throws ParseException {
-        writeString("", bitLength,encoding, value);
+        writeString("", bitLength, encoding, value);
     }
 
-    void popContext(String logicalName);
+    void popContext(String logicalName, WithWriterArgs... writerArgs);
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
index a85815c..b0554a4 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
@@ -63,12 +63,12 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void pushContext(String logicalName) {
+    public void pushContext(String logicalName, WithWriterArgs... writerArgs) {
 
     }
 
     @Override
-    public void writeBit(String logicalName, boolean value) throws ParseException {
+    public void writeBit(String logicalName, boolean value, WithWriterArgs... writerArgs) throws ParseException {
         try {
             bo.writeBoolean(value);
         } catch (IOException e) {
@@ -77,11 +77,11 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeUnsignedByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("unsigned byte must contain at least 1 bit");
         }
-        if(bitLength > 8) {
+        if (bitLength > 8) {
             throw new ParseException("unsigned byte can only contain max 8 bits");
         }
         try {
@@ -92,11 +92,11 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeUnsignedShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("unsigned short must contain at least 1 bit");
         }
-        if(bitLength > 16) {
+        if (bitLength > 16) {
             throw new ParseException("unsigned short can only contain max 16 bits");
         }
         try {
@@ -107,15 +107,15 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeUnsignedInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("unsigned int must contain at least 1 bit");
         }
-        if(bitLength > 32) {
+        if (bitLength > 32) {
             throw new ParseException("unsigned int can only contain max 32 bits");
         }
         try {
-            if(littleEndian) {
+            if (littleEndian) {
                 value = Integer.reverseBytes(value) >> 16;
             }
             bo.writeInt(true, bitLength, value);
@@ -125,15 +125,15 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeUnsignedLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("unsigned long must contain at least 1 bit");
         }
-        if(bitLength > 63) {
+        if (bitLength > 63) {
             throw new ParseException("unsigned long can only contain max 63 bits");
         }
         try {
-            if(littleEndian) {
+            if (littleEndian) {
                 value = Long.reverseBytes(value) >> 32;
             }
             bo.writeLong(true, bitLength, value);
@@ -143,26 +143,26 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
+    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
         try {
             if (bitLength == 64) {
-                if(littleEndian) {
+                if (littleEndian) {
                     if (value.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) >= 0) {
-                        writeLong(logicalName,32, value.longValue());
-                        writeLong(logicalName,32, value.shiftRight(32).longValue());
+                        writeLong(logicalName, 32, value.longValue());
+                        writeLong(logicalName, 32, value.shiftRight(32).longValue());
                     } else {
-                        writeLong(logicalName,bitLength, value.longValue());
+                        writeLong(logicalName, bitLength, value.longValue());
                     }
                 } else {
                     if (value.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) >= 0) {
-                        writeLong(logicalName,32, value.shiftRight(32).longValue());
-                        writeLong(logicalName,32, value.longValue());
+                        writeLong(logicalName, 32, value.shiftRight(32).longValue());
+                        writeLong(logicalName, 32, value.longValue());
                     } else {
-                        writeLong(logicalName,bitLength, value.longValue());
+                        writeLong(logicalName, bitLength, value.longValue());
                     }
                 }
-            } else if (bitLength < 64){
-                writeUnsignedLong(logicalName,bitLength, value.longValue());
+            } else if (bitLength < 64) {
+                writeUnsignedLong(logicalName, bitLength, value.longValue());
             } else {
                 throw new ParseException("Unsigned Big Integer can only contain max 64 bits");
             }
@@ -172,11 +172,11 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeByte(String logicalName, int bitLength, byte value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("byte must contain at least 1 bit");
         }
-        if(bitLength > 8) {
+        if (bitLength > 8) {
             throw new ParseException("byte can only contain max 8 bits");
         }
         try {
@@ -187,15 +187,15 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeShort(String logicalName, int bitLength, short value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("short must contain at least 1 bit");
         }
-        if(bitLength > 16) {
+        if (bitLength > 16) {
             throw new ParseException("short can only contain max 16 bits");
         }
         try {
-            if(littleEndian) {
+            if (littleEndian) {
                 value = Short.reverseBytes(value);
             }
             bo.writeShort(false, bitLength, value);
@@ -205,15 +205,15 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeInt(String logicalName, int bitLength, int value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("int must contain at least 1 bit");
         }
-        if(bitLength > 32) {
+        if (bitLength > 32) {
             throw new ParseException("int can only contain max 32 bits");
         }
         try {
-            if(littleEndian) {
+            if (littleEndian) {
                 value = Integer.reverseBytes(value);
             }
             bo.writeInt(false, bitLength, value);
@@ -223,15 +223,15 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeLong(String logicalName, int bitLength, long value) throws ParseException {
-        if(bitLength <= 0) {
+    public void writeLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException {
+        if (bitLength <= 0) {
             throw new ParseException("long must contain at least 1 bit");
         }
-        if(bitLength > 64) {
+        if (bitLength > 64) {
             throw new ParseException("long can only contain max 64 bits");
         }
         try {
-            if(littleEndian) {
+            if (littleEndian) {
                 value = Long.reverseBytes(value);
             }
             bo.writeLong(false, bitLength, value);
@@ -241,9 +241,9 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
+    public void writeBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
         try {
-            if(bitLength > 64) {
+            if (bitLength > 64) {
                 throw new ParseException("Big Integer can only contain max 64 bits");
             }
             writeLong(logicalName, bitLength, value.longValue());
@@ -253,29 +253,29 @@ public class WriteBufferByteBased implements WriteBuffer {
     }
 
     @Override
-    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException {
+    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
         if (bitsExponent != 8 || bitsMantissa != 23) {
             throw new UnsupportedOperationException("Exponent and/or Mantissa non standard size");
         }
-        writeInt(logicalName,1 + bitsExponent + bitsMantissa, Float.floatToRawIntBits(value));
+        writeInt(logicalName, 1 + bitsExponent + bitsMantissa, Float.floatToRawIntBits(value));
     }
 
     @Override
-    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException {
+    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
         if (bitsExponent != 11 || bitsMantissa != 52) {
             throw new UnsupportedOperationException("Exponent and/or Mantissa non standard size");
         }
-        writeLong(logicalName,1 + bitsExponent + bitsMantissa, Double.doubleToRawLongBits(value));
+        writeLong(logicalName, 1 + bitsExponent + bitsMantissa, Double.doubleToRawLongBits(value));
     }
 
     @Override
-    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException {
+    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value, WithWriterArgs... writerArgs) throws ParseException {
         throw new UnsupportedOperationException("not implemented yet");
     }
 
     @Override
-    public void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException {
-        final byte[] bytes = value.getBytes(Charset.forName(encoding.replaceAll("[^a-zA-Z0-9]","")));
+    public void writeString(String logicalName, int bitLength, String encoding, String value, WithWriterArgs... writerArgs) throws ParseException {
+        final byte[] bytes = value.getBytes(Charset.forName(encoding.replaceAll("[^a-zA-Z0-9]", "")));
         int fixedByteLength = bitLength / 8;
 
         if (bitLength == 0) {
@@ -291,12 +291,12 @@ public class WriteBufferByteBased implements WriteBuffer {
                 }
             }
         } catch (IOException e) {
-           throw new ParseException("Error writing string", e);
+            throw new ParseException("Error writing string", e);
         }
     }
 
     @Override
-    public void popContext(String logicalName) {
+    public void popContext(String logicalName, WithWriterArgs... writerArgs) {
 
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
index 55cff5b..223119e 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
@@ -56,194 +56,176 @@ public class WriteBufferJsonBased implements WriteBuffer, BufferCommons {
     }
 
     @Override
-    public void pushContext(String logicalName) {
-        logicalName = sanitizeLogicalName(logicalName);
+    public void pushContext(String logicalName, WithWriterArgs... writerArgs) {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
         try {
             if (depth == 0) {
                 generator.writeStartObject();
             }
             depth++;
-            // TODO: check if we need to write a array
-            generator.writeObjectFieldStart(logicalName);
+            if (isToBeRenderedAsList(writerArgs)) {
+                generator.writeArrayFieldStart(sanitizedLogicalName);
+            } else {
+                if (generator.getOutputContext().inArray()) {
+                    generator.writeStartObject();
+                }
+                generator.writeObjectFieldStart(sanitizedLogicalName);
+            }
         } catch (IOException e) {
             throw new PlcRuntimeException(e);
         }
     }
 
     @Override
-    public void writeBit(String logicalName, boolean value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwBitKey, 1);
-            generator.writeBooleanField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeBit(String logicalName, boolean value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwBitKey, 1);
+            generator.writeBooleanField(sanitizedLogicalName, value);
+        } );
     }
 
     @Override
-    public void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwUintKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeUnsignedByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwUintKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        } );
     }
 
     @Override
-    public void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
+    public void writeUnsignedShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
             writeAttr(logicalName, rwUintKey, bitLength);
             generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+        });
     }
 
     @Override
-    public void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwUintKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeUnsignedInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwUintKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwUintKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeUnsignedLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwUintKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        } );
     }
 
     @Override
-    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwUintKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwUintKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeByte(String logicalName, int bitLength, byte value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwIntKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwIntKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeShort(String logicalName, int bitLength, short value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwIntKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwIntKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        } );
     }
 
     @Override
-    public void writeInt(String logicalName, int bitLength, int value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwIntKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwIntKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeLong(String logicalName, int bitLength, long value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwIntKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwIntKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwIntKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwIntKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
+    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
             int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
-            writeAttr(logicalName, rwFloatKey, bitLength);
+            writeAttr(sanitizedLogicalName, rwFloatKey, bitLength);
             generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+        });
     }
 
     @Override
-    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
+    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
             int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
-            writeAttr(logicalName, rwFloatKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+            writeAttr(sanitizedLogicalName, rwFloatKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwFloatKey, bitLength);
-            generator.writeNumberField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwFloatKey, bitLength);
+            generator.writeNumberField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException {
-        logicalName = sanitizeLogicalName(logicalName);
-        try {
-            writeAttr(logicalName, rwStringKey, bitLength);
-            generator.writeStringField(String.format("%s__plc4x_%s", logicalName, rwEncodingKey), encoding);
-            generator.writeStringField(logicalName, value);
-        } catch (IOException e) {
-            throw new ParseException("error writing",e);
-        }
+    public void writeString(String logicalName, int bitLength, String encoding, String value, WithWriterArgs... writerArgs) throws ParseException {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
+        wrapIfNecessary(() -> {
+            writeAttr(sanitizedLogicalName, rwStringKey, bitLength);
+            generator.writeStringField(String.format("%s__plc4x_%s", sanitizedLogicalName, rwEncodingKey), encoding);
+            generator.writeStringField(sanitizedLogicalName, value);
+        });
     }
 
     @Override
-    public void popContext(String logicalName) {
-        logicalName = sanitizeLogicalName(logicalName);
+    public void popContext(String logicalName, WithWriterArgs... writerArgs) {
+        final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
         try {
-            // TODO: check if we need to write a array
-            generator.writeEndObject();
+            if (isToBeRenderedAsList(writerArgs)) {
+                generator.writeEndArray();
+            } else {
+                generator.writeEndObject();
+                if (generator.getOutputContext().getParent().inArray()) {
+                    generator.writeEndObject();
+                }
+            }
             depth--;
             if (depth == 0) {
                 generator.writeEndObject();
@@ -253,6 +235,34 @@ public class WriteBufferJsonBased implements WriteBuffer, BufferCommons {
         }
     }
 
+    public void wrapIfNecessary(RunWrapped runnable) throws ParseException {
+        boolean inArray = generator.getOutputContext().inArray();
+        if (inArray) {
+            try {
+                generator.writeStartObject();
+            } catch (IOException e) {
+                throw new ParseException("Error opening wrap", e);
+            }
+        }
+        try {
+            runnable.run();
+        } catch (IOException e) {
+            throw new ParseException("Error running wrap", e);
+        }
+        if (inArray) {
+            try {
+                generator.writeEndObject();
+            } catch (IOException e) {
+                throw new ParseException("Error closing wrap", e);
+            }
+        }
+    }
+
+    @FunctionalInterface
+    private interface RunWrapped {
+        void run() throws IOException, ParseException;
+    }
+
     public String getJsonString() {
         try {
             generator.close();
@@ -262,8 +272,8 @@ public class WriteBufferJsonBased implements WriteBuffer, BufferCommons {
         }
     }
 
-    private void writeAttr(String logicalName , String dataType , int bitLength ) throws IOException {
-        if( !doRenderAttr) {
+    private void writeAttr(String logicalName, String dataType, int bitLength) throws IOException {
+        if (!doRenderAttr) {
             return;
         }
         generator.writeStringField(String.format("%s__plc4x_%s", logicalName, rwDataTypeKey), dataType);
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
index a7b2da1..6589a17 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
@@ -68,7 +68,7 @@ public class WriteBufferXmlBased implements WriteBuffer, BufferCommons {
     }
 
     @Override
-    public void pushContext(String logicalName) {
+    public void pushContext(String logicalName, WithWriterArgs... writerArgs) {
         try {
             indent();
             depth++;
@@ -82,7 +82,7 @@ public class WriteBufferXmlBased implements WriteBuffer, BufferCommons {
     }
 
     @Override
-    public void writeBit(String logicalName, boolean value) throws ParseException {
+    public void writeBit(String logicalName, boolean value, WithWriterArgs... writerArgs) throws ParseException {
         String dataType = "bit";
         int bitLength = 1;
         String data = Boolean.valueOf(value).toString();
@@ -91,93 +91,93 @@ public class WriteBufferXmlBased implements WriteBuffer, BufferCommons {
     }
 
     @Override
-    public void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException {
+    public void writeUnsignedByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwUintKey, bitLength, Byte.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException {
+    public void writeUnsignedShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwUintKey, bitLength, Short.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException {
+    public void writeUnsignedInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwUintKey, bitLength, Integer.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException {
+    public void writeUnsignedLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwUintKey, bitLength, Long.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
+    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwUintKey, bitLength, value.toString());
         move(bitLength);
     }
 
     @Override
-    public void writeByte(String logicalName, int bitLength, byte value) throws ParseException {
+    public void writeByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwIntKey, bitLength, Byte.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeShort(String logicalName, int bitLength, short value) throws ParseException {
+    public void writeShort(String logicalName, int bitLength, short value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwIntKey, bitLength, Short.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeInt(String logicalName, int bitLength, int value) throws ParseException {
+    public void writeInt(String logicalName, int bitLength, int value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwIntKey, bitLength, Integer.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeLong(String logicalName, int bitLength, long value) throws ParseException {
+    public void writeLong(String logicalName, int bitLength, long value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwIntKey, bitLength, Long.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
+    public void writeBigInteger(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwIntKey, bitLength, value.toString());
         move(bitLength);
     }
 
     @Override
-    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException {
+    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
         int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
         createAndAppend(logicalName, rwFloatKey, bitLength, Float.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException {
+    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
         int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
         createAndAppend(logicalName, rwFloatKey, bitLength, Double.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
-    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException {
+    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwFloatKey, bitLength, value.toString());
         move(bitLength);
     }
 
     @Override
-    public void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException {
+    public void writeString(String logicalName, int bitLength, String encoding, String value, WithWriterArgs... writerArgs) throws ParseException {
         createAndAppend(logicalName, rwStringKey, bitLength, value);
         move(bitLength);
     }
 
     @Override
-    public void popContext(String logicalName) {
+    public void popContext(String logicalName, WithWriterArgs... writerArgs) {
         try {
             depth--;
             indent();

[plc4x] 03/04: plc4j: implemented json based read and write buffers.

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit dabe0cf126bae2e43e2db4e6544dddc41a112db7
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Apr 21 13:46:55 2021 +0200

    plc4j: implemented json based read and write buffers.
---
 plc4j/drivers/s7/src/test/java/S7IoTest.java       | 155 ++++++++-
 plc4j/spi/pom.xml                                  |   8 +
 .../plc4x/java/spi/generation/BufferCommons.java   |  40 +++
 .../java/spi/generation/ReadBufferJsonBased.java   | 374 +++++++++++++++++++++
 .../java/spi/generation/ReadBufferXmlBased.java    |  44 ++-
 .../java/spi/generation/WriteBufferJsonBased.java  | 272 +++++++++++++++
 .../java/spi/generation/WriteBufferXmlBased.java   |  46 ++-
 7 files changed, 881 insertions(+), 58 deletions(-)

diff --git a/plc4j/drivers/s7/src/test/java/S7IoTest.java b/plc4j/drivers/s7/src/test/java/S7IoTest.java
index 3b0ca98..1d319d8 100644
--- a/plc4j/drivers/s7/src/test/java/S7IoTest.java
+++ b/plc4j/drivers/s7/src/test/java/S7IoTest.java
@@ -22,7 +22,9 @@ import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
 import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize;
 import org.apache.plc4x.java.s7.readwrite.types.DataTransportErrorCode;
 import org.apache.plc4x.java.s7.readwrite.types.DataTransportSize;
+import org.apache.plc4x.java.spi.generation.ReadBufferJsonBased;
 import org.apache.plc4x.java.spi.generation.ReadBufferXmlBased;
+import org.apache.plc4x.java.spi.generation.WriteBufferJsonBased;
 import org.apache.plc4x.java.spi.generation.WriteBufferXmlBased;
 import org.junit.jupiter.api.Test;
 
@@ -33,6 +35,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class S7IoTest {
 
+    // TODO: delete when done
+    boolean isJsonRenderingDone = false;
+
     @Test
     void TestS7MessageBytes() throws Exception {
         String wantXml =
@@ -100,6 +105,126 @@ public class S7IoTest {
                 "    </COTPPacket>\n" +
                 "  </payload>\n" +
                 "</TPKTPacket>\n";
+        String wantJson ="{\n" +
+            "  \"TPKTPacket\": {\n" +
+            "    \"len\": 29,\n" +
+            "    \"len__plc4x_bitLength\": 16,\n" +
+            "    \"len__plc4x_dataType\": \"uint\",\n" +
+            "    \"payload\": {\n" +
+            "      \"COTPPacket\": {\n" +
+            "        \"COTPPacketData\": {\n" +
+            "          \"eot\": false,\n" +
+            "          \"eot__plc4x_bitLength\": 1,\n" +
+            "          \"eot__plc4x_dataType\": \"bit\",\n" +
+            "          \"tpduRef\": 13,\n" +
+            "          \"tpduRef__plc4x_bitLength\": 7,\n" +
+            "          \"tpduRef__plc4x_dataType\": \"uint\"\n" +
+            "        },\n" +
+            "        \"S7Message\": {\n" +
+            "          \"S7MessageResponseData\": {\n" +
+            "            \"errorClass\": 0,\n" +
+            "            \"errorClass__plc4x_bitLength\": 8,\n" +
+            "            \"errorClass__plc4x_dataType\": \"uint\",\n" +
+            "            \"errorCode\": 0,\n" +
+            "            \"errorCode__plc4x_bitLength\": 8,\n" +
+            "            \"errorCode__plc4x_dataType\": \"uint\"\n" +
+            "          },\n" +
+            "          \"S7Parameter\": {\n" +
+            "            \"S7ParameterReadVarResponse\": {\n" +
+            "              \"numItems\": 1,\n" +
+            "              \"numItems__plc4x_bitLength\": 8,\n" +
+            "              \"numItems__plc4x_dataType\": \"uint\"\n" +
+            "            },\n" +
+            "            \"parameterType\": 4,\n" +
+            "            \"parameterType__plc4x_bitLength\": 8,\n" +
+            "            \"parameterType__plc4x_dataType\": \"uint\"\n" +
+            "          },\n" +
+            "          \"S7Payload\": {\n" +
+            "            \"S7PayloadReadVarResponse\": {\n" +
+            "              \"items\": [\n" +
+            "                {\n" +
+            "                  \"S7VarPayloadDataItem\": {\n" +
+            "                    \"data\": [\n" +
+            "                      {\n" +
+            "                        \"value\": 1\n" +
+            "                      }\n" +
+            "                    ],\n" +
+            "                    \"dataLength\": 1,\n" +
+            "                    \"dataLength__plc4x_bitLength\": 16,\n" +
+            "                    \"dataLength__plc4x_dataType\": \"uint\",\n" +
+            "                    \"padding\": [],\n" +
+            "                    \"returnCode\": {\n" +
+            "                      \"DataTransportErrorCode\": 255,\n" +
+            "                      \"DataTransportErrorCode__plc4x_bitLength\": 8,\n" +
+            "                      \"DataTransportErrorCode__plc4x_dataType\": \"uint\",\n" +
+            "                      \"DataTransportErrorCode__plc4x_stringRepresentation\": \"OK\"\n" +
+            "                    },\n" +
+            "                    \"transportSize\": {\n" +
+            "                      \"DataTransportSize\": 3,\n" +
+            "                      \"DataTransportSize__plc4x_bitLength\": 8,\n" +
+            "                      \"DataTransportSize__plc4x_dataType\": \"uint\",\n" +
+            "                      \"DataTransportSize__plc4x_stringRepresentation\": \"BIT\"\n" +
+            "                    }\n" +
+            "                  }\n" +
+            "                }\n" +
+            "              ]\n" +
+            "            }\n" +
+            "          },\n" +
+            "          \"messageType\": 3,\n" +
+            "          \"messageType__plc4x_bitLength\": 8,\n" +
+            "          \"messageType__plc4x_dataType\": \"uint\",\n" +
+            "          \"parameterLength\": 2,\n" +
+            "          \"parameterLength__plc4x_bitLength\": 16,\n" +
+            "          \"parameterLength__plc4x_dataType\": \"uint\",\n" +
+            "          \"payloadLength\": 5,\n" +
+            "          \"payloadLength__plc4x_bitLength\": 16,\n" +
+            "          \"payloadLength__plc4x_dataType\": \"uint\",\n" +
+            "          \"protocolId\": 50,\n" +
+            "          \"protocolId__plc4x_bitLength\": 8,\n" +
+            "          \"protocolId__plc4x_dataType\": \"uint\",\n" +
+            "          \"reserved\": 0,\n" +
+            "          \"reserved__plc4x_bitLength\": 16,\n" +
+            "          \"reserved__plc4x_dataType\": \"uint\",\n" +
+            "          \"tpduReference\": 11,\n" +
+            "          \"tpduReference__plc4x_bitLength\": 16,\n" +
+            "          \"tpduReference__plc4x_dataType\": \"uint\"\n" +
+            "        },\n" +
+            "        \"headerLength\": 5,\n" +
+            "        \"headerLength__plc4x_bitLength\": 8,\n" +
+            "        \"headerLength__plc4x_dataType\": \"uint\",\n" +
+            "        \"parameters\": [\n" +
+            "          {\n" +
+            "            \"COTPParameter\": {\n" +
+            "              \"COTPParameterTpduSize\": {\n" +
+            "                \"tpduSize\": {\n" +
+            "                  \"COTPTpduSize\": 12,\n" +
+            "                  \"COTPTpduSize__plc4x_bitLength\": 8,\n" +
+            "                  \"COTPTpduSize__plc4x_dataType\": \"int\",\n" +
+            "                  \"COTPTpduSize__plc4x_stringRepresentation\": \"SIZE_4096\"\n" +
+            "                }\n" +
+            "              },\n" +
+            "              \"parameterLength\": 1,\n" +
+            "              \"parameterLength__plc4x_bitLength\": 8,\n" +
+            "              \"parameterLength__plc4x_dataType\": \"uint\",\n" +
+            "              \"parameterType\": 192,\n" +
+            "              \"parameterType__plc4x_bitLength\": 8,\n" +
+            "              \"parameterType__plc4x_dataType\": \"uint\"\n" +
+            "            }\n" +
+            "          }\n" +
+            "        ],\n" +
+            "        \"tpduCode\": 240,\n" +
+            "        \"tpduCode__plc4x_bitLength\": 8,\n" +
+            "        \"tpduCode__plc4x_dataType\": \"uint\"\n" +
+            "      }\n" +
+            "    },\n" +
+            "    \"protocolId\": 3,\n" +
+            "    \"protocolId__plc4x_bitLength\": 8,\n" +
+            "    \"protocolId__plc4x_dataType\": \"uint\",\n" +
+            "    \"reserved\": 0,\n" +
+            "    \"reserved__plc4x_bitLength\": 8,\n" +
+            "    \"reserved__plc4x_dataType\": \"uint\"\n" +
+            "  }\n" +
+            "}\n";
 
 
         TPKTPacket tpktPacket = new TPKTPacket(
@@ -124,13 +249,27 @@ public class S7IoTest {
                 (short) 13
             )
         );
-        WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased();
-        TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket);
-        String gotXml = writeBufferXmlBased.getXmlString();
-        assertEquals(wantXml, gotXml);
-        System.out.println(gotXml);
-        ReadBufferXmlBased readBufferXmlBased = new ReadBufferXmlBased(new ByteArrayInputStream(gotXml.getBytes()));
-        TPKTPacket reReadTpktPacket = TPKTPacketIO.staticParse(readBufferXmlBased);
-        assertThat(reReadTpktPacket).usingRecursiveComparison().isEqualTo(tpktPacket);
+        // Xml
+        {
+            WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased();
+            TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket);
+            String gotXml = writeBufferXmlBased.getXmlString();
+            assertEquals(wantXml, gotXml);
+            ReadBufferXmlBased readBufferXmlBased = new ReadBufferXmlBased(new ByteArrayInputStream(gotXml.getBytes()));
+            TPKTPacket reReadTpktPacket = TPKTPacketIO.staticParse(readBufferXmlBased);
+            assertThat(reReadTpktPacket).usingRecursiveComparison().isEqualTo(tpktPacket);
+        }
+        // json
+        {
+            WriteBufferJsonBased writeBufferJsonBased = new WriteBufferJsonBased();
+            TPKTPacketIO.staticSerialize(writeBufferJsonBased, tpktPacket);
+            String gotJson = writeBufferJsonBased.getJsonString();
+            if (isJsonRenderingDone) {
+                assertEquals(wantJson, gotJson);
+            }
+            ReadBufferJsonBased readBufferXmlBased = new ReadBufferJsonBased(new ByteArrayInputStream(gotJson.getBytes()));
+            TPKTPacket reReadTpktPacket = TPKTPacketIO.staticParse(readBufferXmlBased);
+            assertThat(reReadTpktPacket).usingRecursiveComparison().isEqualTo(tpktPacket);
+        }
     }
 }
diff --git a/plc4j/spi/pom.xml b/plc4j/spi/pom.xml
index ada0e5b..e07baa2 100644
--- a/plc4j/spi/pom.xml
+++ b/plc4j/spi/pom.xml
@@ -57,6 +57,14 @@
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>io.vavr</groupId>
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
new file mode 100644
index 0000000..c3d01d9
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/BufferCommons.java
@@ -0,0 +1,40 @@
+/*
+ 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.generation;
+
+public interface BufferCommons {
+    String rwDataTypeKey             = "dataType";
+    String rwBitLengthKey            = "bitLength";
+    String rwStringRepresentationKey = "stringRepresentation";
+    String rwBitKey                  = "bit";
+    String rwUintKey                 = "uint";
+    String rwIntKey                  = "int";
+    String rwFloatKey                = "float";
+    String rwStringKey               = "string";
+    String rwEncodingKey             = "encoding";
+    String rwIsListKey               = "isList";
+
+    default String sanitizeLogicalName(String logicalName) {
+        if (logicalName.equals("")) {
+            return "value";
+        }
+        return logicalName;
+    }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java
new file mode 100644
index 0000000..46c4736
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferJsonBased.java
@@ -0,0 +1,374 @@
+/*
+ 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.generation;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Stack;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class ReadBufferJsonBased implements ReadBuffer {
+
+    Stack stack;
+
+    Object rootElement;
+
+    int pos;
+
+    boolean doValidateAttr = true;
+
+    public ReadBufferJsonBased(InputStream is) {
+        pos = 1;
+        stack = new Stack<>();
+        // JsonParser here would be overkill as json is by definition not deterministic (key/value)
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            rootElement = mapper.readValue(is, Map.class);
+        } catch (IOException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    @Override
+    public int getPos() {
+        return pos / 8;
+    }
+
+    @Override
+    public boolean hasMore(int numBits) {
+        return false;
+    }
+
+    @Override
+    public void pullContext(String logicalName) {
+        logicalName = sanitizeLogicalName(logicalName);
+        if (stack.empty()) {
+            if (!(rootElement instanceof Map)) {
+                throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, rootElement));
+            }
+            Object context = ((Map)rootElement).get(logicalName);
+            if (context == null) {
+                throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, rootElement));
+            }
+            stack.push(context);
+            return;
+        }
+        Object peek = stack.peek();
+        if (peek.getClass().isArray()) {
+            Object[] contextList = (Object[]) stack.pop();
+            Object context = contextList[0];
+            if (contextList.length < 2) {
+                stack.push(new Object[]{});
+            } else {
+                stack.push(Arrays.copyOfRange(contextList, 1, contextList.length - 1));
+            }
+            Object subContext = ((Map) context).get(logicalName);
+            if (subContext == null) {
+                throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
+            }
+            stack.push(subContext);
+        }
+        if (!(peek instanceof Map)) {
+            throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
+        }
+        Map map = (Map) peek;
+        Object context = map.get(logicalName);
+        if (context == null) {
+            throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
+        }
+        stack.push(context);
+    }
+
+    @Override
+    public boolean readBit(String logicalName) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(1);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "bit", 1);
+        Boolean value = (Boolean) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value;
+    }
+
+    @Override
+    public byte readUnsignedByte(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "uint", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value.byteValue();
+    }
+
+    @Override
+    public short readUnsignedShort(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "uint", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value.shortValue();
+    }
+
+    @Override
+    public int readUnsignedInt(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "uint", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value;
+    }
+
+    @Override
+    public long readUnsignedLong(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "uint", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return Long.valueOf(value);
+    }
+
+    @Override
+    public BigInteger readUnsignedBigInteger(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "uint", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return BigInteger.valueOf(value);
+    }
+
+    @Override
+    public byte readByte(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "int", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value.byteValue();
+    }
+
+    @Override
+    public short readShort(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "int", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value.shortValue();
+    }
+
+    @Override
+    public int readInt(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "int", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value;
+    }
+
+    @Override
+    public long readLong(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "int", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return Long.valueOf(value);
+    }
+
+    @Override
+    public BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "int", bitLength);
+        Integer value = (Integer) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return BigInteger.valueOf(value);
+    }
+
+    @Override
+    public float readFloat(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "float", bitLength);
+        Float value = (Float) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value;
+    }
+
+    @Override
+    public double readDouble(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "float", bitLength);
+        Float value = (Float) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return Double.valueOf(value);
+    }
+
+    @Override
+    public BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "float", bitLength);
+        Float value = (Float) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return BigDecimal.valueOf(value);
+    }
+
+    @Override
+    public String readString(String logicalName, int bitLength, String encoding) {
+        logicalName = sanitizeLogicalName(logicalName);
+        move(bitLength);
+        Map element = getElement(logicalName);
+        validateAttr(logicalName, element, "int", bitLength);
+        String value = (String) element.get(logicalName);
+        if (value == null) {
+            throw new PlcRuntimeException(String.format("Required element %s not found in %s", logicalName, stack.peek()));
+        }
+        return value;
+    }
+
+    @Override
+    public void closeContext(String logicalName) {
+        logicalName = sanitizeLogicalName(logicalName);
+        if (stack.empty()) {
+            throw new PlcRuntimeException(String.format("Required context close %s not found in %s", logicalName, rootElement));
+        }
+        // Delete us from stack
+        stack.pop();
+        if (stack.empty()) {
+            return;
+        }
+        Object peek =stack.peek();
+        if (peek.getClass().isArray()) {
+            return;
+        }
+        Map map = (Map) peek;
+        if (map.get(logicalName)==null) {
+            throw new PlcRuntimeException(String.format("Required context %s not found in %s", logicalName, peek));
+        }
+        map.remove(logicalName);
+    }
+
+
+    private Map getElement(String logicalName) {
+        logicalName = sanitizeLogicalName(logicalName);
+        Object peek = stack.peek();
+        Map element;
+        if (peek.getClass().isArray()) {
+            Object pop = stack.pop();
+            Object[] elementList = (Object[]) pop;
+            element = (Map) elementList[0];
+            if (elementList.length < 2) {
+                stack.push(new Object[]{});
+            } else {
+                stack.push(Arrays.copyOfRange(elementList, 1, elementList.length - 1));
+            }
+            return element;
+        } else if (peek instanceof Map) {
+            return (Map) peek;
+        } else {
+            throw new PlcRuntimeException(String.format("Invalid state at %s with %s", logicalName, peek));
+        }
+    }
+
+
+    private void validateAttr(String logicalName, Map element, String dataType, int bitLength) {
+        if (!doValidateAttr) {
+            return;
+        }
+        String renderedKeyDataLengthKey = String.format("%s__plc4x_%s", logicalName, "dataType");
+        String actualDataType = (String) element.get(renderedKeyDataLengthKey);
+        if (!dataType.equals(actualDataType)) {
+            throw new PlcRuntimeException(String.format("Unexpected %s :%s. Want %s", renderedKeyDataLengthKey, actualDataType, dataType));
+        }
+        String renderedBitLengthKey = String.format("%s__plc4x_%s", logicalName, "bitLength");
+        Integer actualBitLength = (Integer) element.get(renderedBitLengthKey);
+        if (bitLength !=actualBitLength) {
+            throw new PlcRuntimeException(String.format("Unexpected %s :%s. Want %s", renderedBitLengthKey, actualBitLength, bitLength));
+        }
+    }
+
+
+    private String sanitizeLogicalName(String logicalName) {
+        if (logicalName.equals("")) {
+            return "value";
+        }
+        return logicalName;
+    }
+
+
+    private void move(int bits) {
+        pos += bits;
+    }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
index 2f2f90d..a63d5ab 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
@@ -30,7 +30,7 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Iterator;
 
-public class ReadBufferXmlBased implements ReadBuffer {
+public class ReadBufferXmlBased implements ReadBuffer, BufferCommons {
 
     XMLEventReader reader;
 
@@ -66,7 +66,7 @@ public class ReadBufferXmlBased implements ReadBuffer {
 
     @Override
     public boolean readBit(String logicalName) throws ParseException {
-        String bit = decode(logicalName, "bit", 1);
+        String bit = decode(logicalName, rwBitKey, 1);
         move(1);
         return bit.equals("1");
     }
@@ -74,25 +74,25 @@ public class ReadBufferXmlBased implements ReadBuffer {
     @Override
     public byte readUnsignedByte(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Byte.parseByte(decode(logicalName, "uint", bitLength));
+        return Byte.parseByte(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
     public short readUnsignedShort(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Short.parseShort(decode(logicalName, "uint", bitLength));
+        return Short.parseShort(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
     public int readUnsignedInt(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Integer.parseInt(decode(logicalName, "uint", bitLength));
+        return Integer.parseInt(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
     public long readUnsignedLong(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Long.parseLong(decode(logicalName, "uint", bitLength));
+        return Long.parseLong(decode(logicalName, rwUintKey, bitLength));
     }
 
     @Override
@@ -104,55 +104,55 @@ public class ReadBufferXmlBased implements ReadBuffer {
     @Override
     public byte readByte(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Byte.parseByte(decode(logicalName, "int", bitLength));
+        return Byte.parseByte(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
     public short readShort(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Short.parseShort(decode(logicalName, "int", bitLength));
+        return Short.parseShort(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
     public int readInt(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Integer.parseInt(decode(logicalName, "int", bitLength));
+        return Integer.parseInt(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
     public long readLong(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Long.parseLong(decode(logicalName, "int", bitLength));
+        return Long.parseLong(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
     public BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return new BigInteger(decode(logicalName,"int",bitLength));
+        return new BigInteger(decode(logicalName, rwIntKey, bitLength));
     }
 
     @Override
     public float readFloat(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Float.parseFloat(decode(logicalName, "float", bitLength));
+        return Float.parseFloat(decode(logicalName, rwFloatKey, bitLength));
     }
 
     @Override
     public double readDouble(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return Double.parseDouble(decode(logicalName, "float", bitLength));
+        return Double.parseDouble(decode(logicalName, rwFloatKey, bitLength));
     }
 
     @Override
     public BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException {
         move(bitLength);
-        return new BigDecimal(decode(logicalName, "float", bitLength));
+        return new BigDecimal(decode(logicalName, rwFloatKey, bitLength));
     }
 
     @Override
     public String readString(String logicalName, int bitLength, String encoding) {
         move(bitLength);
-        return decode(logicalName, "string", bitLength);
+        return decode(logicalName, rwStringKey, bitLength);
     }
 
     @Override
@@ -234,12 +234,12 @@ public class ReadBufferXmlBased implements ReadBuffer {
         boolean bitLengthValidate = false;
         while (attr.hasNext()) {
             Attribute attribute = attr.next();
-            if (attribute.getName().getLocalPart().equals("dataType")) {
+            if (attribute.getName().getLocalPart().equals(rwDataTypeKey)) {
                 if (!attribute.getValue().equals(dataType)) {
                     throw new PlcRuntimeException(String.format("Unexpected dataType :%s. Want %s", attribute.getValue(), dataType));
                 }
                 dataTypeValidated = true;
-            } else if (attribute.getName().getLocalPart().equals("bitLength")) {
+            } else if (attribute.getName().getLocalPart().equals(rwBitLengthKey)) {
                 if (!attribute.getValue().equals(Integer.valueOf(bitLength).toString())) {
                     throw new PlcRuntimeException(String.format("Unexpected bitLength '%s'. Want '%d'", attribute.getValue(), bitLength));
                 }
@@ -247,18 +247,12 @@ public class ReadBufferXmlBased implements ReadBuffer {
             }
         }
         if (!dataTypeValidated) {
-            throw new PlcRuntimeException("required attribute dataType missing");
+            throw new PlcRuntimeException(String.format("required attribute %s missing",rwDataTypeKey));
         }
         if (!bitLengthValidate) {
-            throw new PlcRuntimeException("required attribute bitLength missing");
+            throw new PlcRuntimeException(String.format("required attribute %s missing",rwBitLengthKey));
         }
         return true;
     }
 
-    private String sanitizeLogicalName(String logicalName) {
-        if (logicalName.equals("")) {
-            return "value";
-        }
-        return logicalName;
-    }
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
new file mode 100644
index 0000000..55cff5b
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
@@ -0,0 +1,272 @@
+/*
+ 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.generation;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonFactoryBuilder;
+import com.fasterxml.jackson.core.JsonGenerator;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class WriteBufferJsonBased implements WriteBuffer, BufferCommons {
+
+    ByteArrayOutputStream byteArrayOutputStream;
+
+    JsonGenerator generator;
+
+    int depth = 0;
+
+    boolean doRenderAttr = true;
+
+    public WriteBufferJsonBased() {
+        byteArrayOutputStream = new ByteArrayOutputStream();
+        JsonFactory jsonFactory = new JsonFactoryBuilder()
+            .build();
+        try {
+            generator = jsonFactory.createGenerator(byteArrayOutputStream).useDefaultPrettyPrinter();
+        } catch (IOException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    @Override
+    public int getPos() {
+        return 0;
+    }
+
+    @Override
+    public void pushContext(String logicalName) {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            if (depth == 0) {
+                generator.writeStartObject();
+            }
+            depth++;
+            // TODO: check if we need to write a array
+            generator.writeObjectFieldStart(logicalName);
+        } catch (IOException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void writeBit(String logicalName, boolean value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwBitKey, 1);
+            generator.writeBooleanField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwUintKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwUintKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwUintKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwUintKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwUintKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeByte(String logicalName, int bitLength, byte value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwIntKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeShort(String logicalName, int bitLength, short value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwIntKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeInt(String logicalName, int bitLength, int value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwIntKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeLong(String logicalName, int bitLength, long value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwIntKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwIntKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
+            writeAttr(logicalName, rwFloatKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
+            writeAttr(logicalName, rwFloatKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwFloatKey, bitLength);
+            generator.writeNumberField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            writeAttr(logicalName, rwStringKey, bitLength);
+            generator.writeStringField(String.format("%s__plc4x_%s", logicalName, rwEncodingKey), encoding);
+            generator.writeStringField(logicalName, value);
+        } catch (IOException e) {
+            throw new ParseException("error writing",e);
+        }
+    }
+
+    @Override
+    public void popContext(String logicalName) {
+        logicalName = sanitizeLogicalName(logicalName);
+        try {
+            // TODO: check if we need to write a array
+            generator.writeEndObject();
+            depth--;
+            if (depth == 0) {
+                generator.writeEndObject();
+            }
+        } catch (IOException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    public String getJsonString() {
+        try {
+            generator.close();
+            return byteArrayOutputStream.toString("UTF-8");
+        } catch (IOException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    private void writeAttr(String logicalName , String dataType , int bitLength ) throws IOException {
+        if( !doRenderAttr) {
+            return;
+        }
+        generator.writeStringField(String.format("%s__plc4x_%s", logicalName, rwDataTypeKey), dataType);
+        generator.writeNumberField(String.format("%s__plc4x_%s", logicalName, rwBitLengthKey), bitLength);
+    }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
index 0d2a583..a7b2da1 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
@@ -26,15 +26,17 @@ import javax.xml.stream.XMLEventFactory;
 import javax.xml.stream.XMLEventWriter;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.*;
-
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
 import java.io.ByteArrayOutputStream;
 import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Stack;
 
-public class WriteBufferXmlBased implements WriteBuffer {
+public class WriteBufferXmlBased implements WriteBuffer, BufferCommons {
 
     Stack<String> stack;
 
@@ -90,87 +92,87 @@ public class WriteBufferXmlBased implements WriteBuffer {
 
     @Override
     public void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException {
-        createAndAppend(logicalName, "uint", bitLength, Byte.valueOf(value).toString());
+        createAndAppend(logicalName, rwUintKey, bitLength, Byte.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException {
-        createAndAppend(logicalName, "uint", bitLength, Short.valueOf(value).toString());
+        createAndAppend(logicalName, rwUintKey, bitLength, Short.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException {
-        createAndAppend(logicalName, "uint", bitLength, Integer.valueOf(value).toString());
+        createAndAppend(logicalName, rwUintKey, bitLength, Integer.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException {
-        createAndAppend(logicalName, "uint", bitLength, Long.valueOf(value).toString());
+        createAndAppend(logicalName, rwUintKey, bitLength, Long.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
-        createAndAppend(logicalName, "uint", bitLength, value.toString());
+        createAndAppend(logicalName, rwUintKey, bitLength, value.toString());
         move(bitLength);
     }
 
     @Override
     public void writeByte(String logicalName, int bitLength, byte value) throws ParseException {
-        createAndAppend(logicalName, "int", bitLength, Byte.valueOf(value).toString());
+        createAndAppend(logicalName, rwIntKey, bitLength, Byte.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeShort(String logicalName, int bitLength, short value) throws ParseException {
-        createAndAppend(logicalName, "int", bitLength, Short.valueOf(value).toString());
+        createAndAppend(logicalName, rwIntKey, bitLength, Short.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeInt(String logicalName, int bitLength, int value) throws ParseException {
-        createAndAppend(logicalName, "int", bitLength, Integer.valueOf(value).toString());
+        createAndAppend(logicalName, rwIntKey, bitLength, Integer.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeLong(String logicalName, int bitLength, long value) throws ParseException {
-        createAndAppend(logicalName, "int", bitLength, Long.valueOf(value).toString());
+        createAndAppend(logicalName, rwIntKey, bitLength, Long.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException {
-        createAndAppend(logicalName, "int", bitLength, value.toString());
+        createAndAppend(logicalName, rwIntKey, bitLength, value.toString());
         move(bitLength);
     }
 
     @Override
     public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException {
         int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
-        createAndAppend(logicalName, "float", bitLength, Float.valueOf(value).toString());
+        createAndAppend(logicalName, rwFloatKey, bitLength, Float.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException {
         int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
-        createAndAppend(logicalName, "float", bitLength, Double.valueOf(value).toString());
+        createAndAppend(logicalName, rwFloatKey, bitLength, Double.valueOf(value).toString());
         move(bitLength);
     }
 
     @Override
     public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException {
-        createAndAppend(logicalName, "float", bitLength, value.toString());
+        createAndAppend(logicalName, rwFloatKey, bitLength, value.toString());
         move(bitLength);
     }
 
     @Override
     public void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException {
-        createAndAppend(logicalName, "string", bitLength, value);
+        createAndAppend(logicalName, rwStringKey, bitLength, value);
         move(bitLength);
     }
 
@@ -226,9 +228,9 @@ public class WriteBufferXmlBased implements WriteBuffer {
             indent();
             StartElement startElement = xmlEventFactory.createStartElement("", "", sanitizeLogicalName(logicalName));
             xmlEventWriter.add(startElement);
-            Attribute dataTypeAttribute = xmlEventFactory.createAttribute("dataType", dataType);
+            Attribute dataTypeAttribute = xmlEventFactory.createAttribute(rwDataTypeKey, dataType);
             xmlEventWriter.add(dataTypeAttribute);
-            Attribute bitLengthAttribute = xmlEventFactory.createAttribute("bitLength", String.valueOf(bitLength));
+            Attribute bitLengthAttribute = xmlEventFactory.createAttribute(rwBitLengthKey, String.valueOf(bitLength));
             xmlEventWriter.add(bitLengthAttribute);
             Characters dataCharacters = xmlEventFactory.createCharacters(data);
             xmlEventWriter.add(dataCharacters);
@@ -240,10 +242,4 @@ public class WriteBufferXmlBased implements WriteBuffer {
         }
     }
 
-    private String sanitizeLogicalName(String logicalName) {
-        if (logicalName.equals("")) {
-            return "value";
-        }
-        return logicalName;
-    }
 }

[plc4x] 01/04: plc4go: enable validation on ReadBufferJsonBased by default

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit f19f42b74440d65e332c1288360903c53c00e324
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Apr 21 13:26:18 2021 +0200

    plc4go: enable validation on ReadBufferJsonBased by default
    
    + fixed some bugs and added todos for missing value datatypes
---
 .../plc4go/spi/utils/ReadBufferJsonBased.go        | 50 +++++++++++-----------
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git a/plc4go/internal/plc4go/spi/utils/ReadBufferJsonBased.go b/plc4go/internal/plc4go/spi/utils/ReadBufferJsonBased.go
index 51942e6..bfef01d 100644
--- a/plc4go/internal/plc4go/spi/utils/ReadBufferJsonBased.go
+++ b/plc4go/internal/plc4go/spi/utils/ReadBufferJsonBased.go
@@ -35,7 +35,7 @@ func NewJsonReadBuffer(reader io.Reader) ReadBuffer {
 	return &jsonReadBuffer{
 		rootElement:    rootElement,
 		pos:            1,
-		doValidateAttr: false,
+		doValidateAttr: true,
 		err:            err,
 	}
 }
@@ -129,7 +129,7 @@ func (j *jsonReadBuffer) ReadBit(logicalName string, readerArgs ...WithReaderArg
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(1)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "bit", 1, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "bit", 1, readerArgs...); err != nil {
 		return false, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -146,7 +146,7 @@ func (j *jsonReadBuffer) ReadUint8(logicalName string, bitLength uint8, readerAr
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "uint", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "uint", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -163,7 +163,7 @@ func (j *jsonReadBuffer) ReadUint16(logicalName string, bitLength uint8, readerA
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "uint", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "uint", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -180,7 +180,7 @@ func (j *jsonReadBuffer) ReadUint32(logicalName string, bitLength uint8, readerA
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "uint", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "uint", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -197,7 +197,7 @@ func (j *jsonReadBuffer) ReadUint64(logicalName string, bitLength uint8, readerA
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "uint", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "uint", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -214,7 +214,7 @@ func (j *jsonReadBuffer) ReadInt8(logicalName string, bitLength uint8, readerArg
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "int", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "int", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -231,7 +231,7 @@ func (j *jsonReadBuffer) ReadInt16(logicalName string, bitLength uint8, readerAr
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "int", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "int", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -248,7 +248,7 @@ func (j *jsonReadBuffer) ReadInt32(logicalName string, bitLength uint8, readerAr
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "int", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "int", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -265,7 +265,7 @@ func (j *jsonReadBuffer) ReadInt64(logicalName string, bitLength uint8, readerAr
 	logicalName = j.sanitizeLogicalName(logicalName)
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "int", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "int", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -283,7 +283,7 @@ func (j *jsonReadBuffer) ReadBigInt(logicalName string, bitLength uint64, reader
 	logicalName = j.sanitizeLogicalName(logicalName)
 	peek, element := j.getElement(logicalName)
 	// TODO: not enough bits
-	if err := j.validateAttr(element, "int", uint8(bitLength), readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "int", uint8(bitLength), readerArgs...); err != nil {
 		return nil, err
 	}
 	newInt := big.NewInt(0)
@@ -306,7 +306,7 @@ func (j *jsonReadBuffer) ReadFloat32(logicalName string, signed bool, exponentBi
 	}
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "float", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "float", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -327,7 +327,7 @@ func (j *jsonReadBuffer) ReadFloat64(logicalName string, signed bool, exponentBi
 	}
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "float", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "float", bitLength, readerArgs...); err != nil {
 		return 0, err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -348,7 +348,7 @@ func (j *jsonReadBuffer) ReadBigFloat(logicalName string, signed bool, exponentB
 	}
 	j.move(bitLength)
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "float", bitLength, readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "float", bitLength, readerArgs...); err != nil {
 		return nil, err
 	}
 	newFloat := big.NewFloat(0)
@@ -368,7 +368,7 @@ func (j *jsonReadBuffer) ReadString(logicalName string, bitLength uint32, reader
 	// TODO: not enough bits
 	j.move(uint8(bitLength))
 	peek, element := j.getElement(logicalName)
-	if err := j.validateAttr(element, "string", uint8(bitLength), readerArgs...); err != nil {
+	if err := j.validateAttr(logicalName, element, "string", uint8(bitLength), readerArgs...); err != nil {
 		return "", err
 	}
 	if value, ok := element[logicalName]; ok {
@@ -418,11 +418,6 @@ func (j *jsonReadBuffer) getElement(logicalName string) (interface{}, map[string
 		} else {
 			j.Push(elementList[1 : len(elementList)-1])
 		}
-	case []map[string]interface{}:
-		pop := j.Pop()
-		elementList := pop.([]map[string]interface{})
-		element = elementList[0]
-		j.Push(elementList[1 : len(elementList)-1])
 	case map[string]interface{}:
 		element = peek.(map[string]interface{})
 	default:
@@ -435,15 +430,18 @@ func (j *jsonReadBuffer) move(bits uint8) {
 	j.pos += uint(bits)
 }
 
-func (j *jsonReadBuffer) validateAttr(element map[string]interface{}, dataType string, bitLength uint8, readerArgs ...WithReaderArgs) error {
-	if !j.doValidateAttr {
+func (j *jsonReadBuffer) validateAttr(logicalName string, element map[string]interface{}, dataType string, bitLength uint8, readerArgs ...WithReaderArgs) error {
+	// TODO: why is the type and length missing for values. Fix this
+	if !j.doValidateAttr || logicalName == "value" {
 		return nil
 	}
-	if value, ok := element[rwDataTypeKey]; !ok || value != dataType {
-		return errors.Errorf("Unexpected %s :%s. Want %s", rwDataTypeKey, dataType, dataType)
+	renderedKeyDataLengthKey := fmt.Sprintf("%s__plc4x_%s", logicalName, rwDataTypeKey)
+	if value, ok := element[renderedKeyDataLengthKey]; !ok || value != dataType {
+		return errors.Errorf("Unexpected %s :%s. Want %s", renderedKeyDataLengthKey, value, dataType)
 	}
-	if value, ok := element[rwBitLengthKey]; !ok || value != string(bitLength) {
-		return errors.Errorf("Unexpected %s :%d. Want %s", rwBitLengthKey, bitLength, dataType)
+	renderedBitLengthKey := fmt.Sprintf("%s__plc4x_%s", logicalName, rwBitLengthKey)
+	if value, ok := element[renderedBitLengthKey]; !ok || uint8(value.(float64)) != bitLength {
+		return errors.Errorf("Unexpected %s :%d. Want %d", renderedBitLengthKey, value, bitLength)
 	}
 	return nil
 }