You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/01/22 15:01:01 UTC

[plc4x] branch develop updated: - Added a toPlcValue to the Message interface - Made the code generation implement the additional method - Refactored the code generation to have the IO classes implement MessageIO or MessageInput - Renamed the static parse method staticParse and the static serialize staticSerialize - Updated the rest of the project to use the updated method names - Updated the GeneratedProtocolMessageCodec to use the now enhanced IO classes - Got rid of the ReflectionBasedIo as well as Parser and Serializ [...]

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new a9ebc4c  - Added a toPlcValue to the Message interface - Made the code generation implement the additional method - Refactored the code generation to have the IO classes implement MessageIO or MessageInput - Renamed the static parse method staticParse and the static serialize staticSerialize - Updated the rest of the project to use the updated method names - Updated the GeneratedProtocolMessageCodec to use the now enhanced IO classes - Got rid of the ReflectionBasedIo as well as  [...]
a9ebc4c is described below

commit a9ebc4cc4bb989b2a653df2ac9eecb7a8b134cfb
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Jan 22 16:00:52 2020 +0100

    - Added a toPlcValue to the Message interface
    - Made the code generation implement the additional method
    - Refactored the code generation to have the IO classes implement MessageIO or MessageInput
    - Renamed the static parse method staticParse and the static serialize staticSerialize
    - Updated the rest of the project to use the updated method names
    - Updated the GeneratedProtocolMessageCodec to use the now enhanced IO classes
    - Got rid of the ReflectionBasedIo as well as Parser and Serializer in the SPI module
---
 .../resources/templates/java/data-io-template.ftlh | 14 ++--
 .../main/resources/templates/java/io-template.ftlh | 63 ++++++++++++++----
 .../resources/templates/java/pojo-template.ftlh    | 68 +++++++++++++++++++-
 .../org/apache/plc4x/java/abeth/AbEthDriver.java   |  3 +-
 .../apache/plc4x/java/knxnetip/KnxNetIpDriver.java |  3 +-
 .../knxnetip/protocol/KnxNetIpProtocolLogic.java   |  2 +-
 .../org/apache/plc4x/java/knxnetip/IOTest.java     |  4 +-
 .../apache/plc4x/java/knxnetip/ManualKnxNetIp.java |  7 ++
 .../java/knxnetip/ManualKnxNetIpWithEts5.java      |  4 +-
 .../connection/GeneratedProtocolMessageCodec.java  | 17 +----
 .../apache/plc4x/java/spi/connection/Parser.java   | 29 ---------
 .../java/spi/connection/ReflectionBasedIo.java     | 74 ----------------------
 .../plc4x/java/spi/connection/Serializer.java      | 29 ---------
 .../connection/SingleProtocolStackConfigurer.java  | 27 +++++---
 .../apache/plc4x/java/spi/generation/Message.java  |  4 ++
 .../plc4x/java/spi/generation/MessageOutput.java   |  2 +-
 .../test/protocol/ProtocolTestsuiteRunner.java     |  6 +-
 .../server/s7/protocol/S7Step7Protocol.java        |  6 +-
 .../apache/plc4x/java/amsads/AMSADSPlcDriver.java  |  3 +-
 .../java/amsads/protocol/Ads2PayloadProtocol.java  |  4 +-
 .../amsads/protocol/Payload2SerialProtocol.java    |  8 +--
 .../java/amsads/protocol/Payload2TcpProtocol.java  |  8 +--
 .../plc4x/java/bacnetip/PassiveBacNetIpDriver.java |  3 +-
 .../plc4x/java/bacnetip/ManualBacNetDecoder.java   |  2 +-
 .../org/apache/plc4x/java/df1/DF1PlcDriver.java    |  3 +-
 .../plc4x/java/df1/protocol/Df1Protocol.java       |  4 +-
 .../org/apache/plc4x/java/modbus/ModbusDriver.java |  3 +-
 .../apache/plc4x/java/s7/readwrite/S7Driver.java   |  3 +-
 .../s7/readwrite/protocol/S7ProtocolLogic.java     |  4 +-
 .../src/test/java/BenchmarkGeneratedS7.java        |  4 +-
 sandbox/test-streampipes-plc4x-adapters/pom.xml    |  6 +-
 sandbox/test-streampipes-plc4x-processors/pom.xml  |  9 +--
 .../enrich/knxnetip/ets5/Ets5DataEnrichment.java   |  2 +-
 33 files changed, 206 insertions(+), 222 deletions(-)

diff --git a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
index 4659ed2..ede70bc 100644
--- a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
@@ -62,7 +62,7 @@ public class ${typeName}IO {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(${typeName}IO.class);
 
-    public static PlcValue parse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static PlcValue staticParse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(type.switchField.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
             <#list case.fields as field>
                 <#assign skipReturn=false>
@@ -85,7 +85,7 @@ public class ${typeName}IO {
                 int itemCount = (int) ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc};
                 ${field.name} = new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[itemCount];
                 for(int curItem = 0; curItem < itemCount; curItem++) {
-                    ${field.name}[curItem] = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>;
+                    ${field.name}[curItem] = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>;
                 }
             }
             <#-- In all other cases do we have to work with a list, that is later converted to an array -->
@@ -97,7 +97,7 @@ public class ${typeName}IO {
             List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
             int ${field.name}EndPos = io.getPos() + _${field.name}Length;
             while(io.getPos() < ${field.name}EndPos) {
-                _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+                _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
                 <#-- After parsing, update the current position, but only if it's needed -->
                                 <#if field.loopExpression.contains("curPos")>
                 curPos = io.getPos() - startPos;
@@ -108,7 +108,7 @@ public class ${typeName}IO {
             // Terminated array
             List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
             while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc}))) {
-                _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+                _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
 
                 <#-- After parsing, update the current position, but only if it's needed -->
                                 <#if field.loopExpression.contains("curPos")>
@@ -185,7 +185,7 @@ public class ${typeName}IO {
                     <#case "simple">
 
             // Simple Field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
                     <#break>
                 </#switch>
             </#list>
@@ -225,7 +225,7 @@ public class ${typeName}IO {
     }
 
 <#if outputFlavor != "passive">
-    public static WriteBuffer serialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static WriteBuffer staticSerialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(type.switchField.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
             WriteBuffer io = new WriteBuffer(${helper.getSizeInBits(case)});
             <#list case.fields as field>
@@ -264,7 +264,7 @@ public class ${typeName}IO {
                         <#if helper.isSimpleType(field.type)>
             ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
                         <#else>
-            ${field.type.name}IO.serialize(io, ${field.name});
+            ${field.type.name}IO.staticSerialize(io, ${field.name});
                         </#if>
                     <#break>
                 </#switch>
diff --git a/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
index 8fe1f92..ade6dd2 100644
--- a/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
@@ -43,6 +43,7 @@ import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
 <#if helper.getComplexTypes(type)?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if>
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.spi.generation.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,11 +55,47 @@ import java.time.*;
 import java.util.*;
 import java.util.function.Supplier;
 
-public class ${typeName}IO {
+public class ${typeName}IO <#if !helper.isDiscriminatedType(type)>implements <#if outputFlavor != "passive">MessageIO<${typeName}, ${typeName}><#else>MessageInput<${typeName}></#if></#if> {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(${typeName}IO.class);
 
-    public static ${typeName}<#if helper.isDiscriminatedType(type)>Builder</#if> parse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+<#if !helper.isDiscriminatedType(type)>
+    @Override
+    public ${typeName} parse(ReadBuffer io, Object... args) throws ParseException {
+        <#if type.parserArguments?has_content>
+        if((args == null) || (args.length != ${type.parserArguments?size})) {
+            throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length);
+        }
+        <#list type.parserArguments as parserArgument>
+        if(!(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeName(parserArgument.type, false)})) {
+            throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeName(parserArgument.type, false)} but was " + args[${parserArgument?index}].getClass().getName());
+        }
+        ${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name} = (${helper.getLanguageTypeName(parserArgument.type, false)}) args[${parserArgument?index}];
+        </#list>
+        </#if>
+        return ${typeName}IO.staticParse(io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+    }
+
+    <#if outputFlavor != "passive">
+    @Override
+    public void serialize(WriteBuffer io, ${typeName} value, Object... args) throws ParseException {
+        <#if helper.getSerializerArguments(type.parserArguments)?has_content>
+        if((args == null) || (args.length != ${type.parserArguments?size})) {
+            throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length);
+        }
+        <#list helper.getSerializerArguments(type.parserArguments) as serializerArgument>
+        if(!(args[${serializerArgument?index}] instanceof ${helper.getLanguageTypeName(serializerArgument.type, false)})) {
+            throw new PlcRuntimeException("Argument ${serializerArgument?index} expected to be of type ${helper.getLanguageTypeName(serializerArgument.type, false)} but was " + args[${serializerArgument?index}].getClass().getName());
+        }
+        ${helper.getLanguageTypeName(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeName(serializerArgument.type, false)}) args[${serializerArgument?index}];
+        </#list>
+        </#if>
+        ${typeName}IO.staticSerialize(io, value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+    }
+
+    </#if>
+</#if>
+    public static ${typeName}<#if helper.isDiscriminatedType(type)>Builder</#if> staticParse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         int startPos = io.getPos();
         int curPos;
 <#list type.fields as field>
@@ -82,7 +119,7 @@ public class ${typeName}IO {
             ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
             for(int curItem = 0; curItem < itemCount; curItem++) {
                 <#if !helper.isSimpleType(field.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
-                ${field.name}[curItem] = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>;
+                ${field.name}[curItem] = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>;
             }
         }
         <#-- In all other cases do we have to work with a list, that is later converted to an array -->
@@ -94,7 +131,7 @@ public class ${typeName}IO {
         List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
         int ${field.name}EndPos = io.getPos() + _${field.name}Length;
         while(io.getPos() < ${field.name}EndPos) {
-            _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+            _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
             <#-- After parsing, update the current position, but only if it's needed -->
             <#if field.loopExpression.contains("curPos")>
             curPos = io.getPos() - startPos;
@@ -105,7 +142,7 @@ public class ${typeName}IO {
         // Terminated array
         List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
         while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc}))) {
-            _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+            _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
 
             <#-- After parsing, update the current position, but only if it's needed -->
             <#if field.loopExpression.contains("curPos")>
@@ -236,7 +273,7 @@ public class ${typeName}IO {
         </#if>
         ${helper.getLanguageTypeNameForField(field)} ${field.name} = null;
         if(${helper.toParseExpression(field, field.conditionExpression, type.parserArguments)?no_esc}) {
-            ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+            ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
         }
         <#break>
     <#case "padding">
@@ -261,7 +298,7 @@ public class ${typeName}IO {
     <#case "simple">
 
         // Simple Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+        ${helper.getLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
         <#break>
     <#case "switch">
 
@@ -269,7 +306,7 @@ public class ${typeName}IO {
         ${typeName}Builder builder = null;
         <#list field.cases as case>
         <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(field.discriminatorNames[discriminatorValue?index])?no_esc}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{
-            builder = ${case.name}IO.parse(io<#if case.parserArguments?has_content>, <#list case.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+            builder = ${case.name}IO.staticParse(io<#if case.parserArguments?has_content>, <#list case.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
         }<#sep> else </#sep>
         </#list>
         if (builder == null) {
@@ -296,7 +333,7 @@ public class ${typeName}IO {
     }
 
 <#if outputFlavor != "passive">
-    public static void serialize(WriteBuffer io, ${typeName} _value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static void staticSerialize(WriteBuffer io, ${typeName} _value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         int startPos = io.getPos();
 
 <#list type.fields as field>
@@ -312,7 +349,7 @@ public class ${typeName}IO {
                 ${helper.getWriteBufferReadMethodCall(field.type, "element")?no_esc};
                 <#else>
                 boolean lastItem = curItem == (itemCount - 1);
-                ${field.type.name}IO.serialize(io, element<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+                ${field.type.name}IO.staticSerialize(io, element<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
                 </#if>
                 curItem++;
             }
@@ -375,7 +412,7 @@ public class ${typeName}IO {
             <#if helper.isSimpleType(field.type)>
             ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
             <#else>
-            ${field.type.name}IO.serialize(io, ${field.name});
+            ${field.type.name}IO.staticSerialize(io, ${field.name});
             </#if>
         }
         <#break>
@@ -400,7 +437,7 @@ public class ${typeName}IO {
         <#if helper.isSimpleType(field.type)>
         ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
         <#else>
-        ${field.type.name}IO.serialize(io, ${field.name});
+        ${field.type.name}IO.staticSerialize(io, ${field.name});
         </#if>
         <#break>
     <#case "switch">
@@ -408,7 +445,7 @@ public class ${typeName}IO {
         // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
         <#list field.cases as case>
         if(_value instanceof ${case.name}) {
-            ${case.name}IO.serialize(io, (${case.name}) _value);
+            ${case.name}IO.staticSerialize(io, (${case.name}) _value);
         }<#sep> else </#sep>
         </#list>
         <#break>
diff --git a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
index 0606def..967da92 100644
--- a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
@@ -45,10 +45,11 @@ import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
 import com.fasterxml.jackson.annotation.*;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.plc4x.java.api.value.*;
 import org.apache.plc4x.java.spi.generation.Message;
 
 import java.time.*;
-import java.util.Objects;
+import java.util.*;
 import java.math.BigInteger;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
@@ -215,6 +216,71 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
         return lengthInBits / 8;
     }
 
+    public PlcValue toPlcValue() {
+<#if type.propertyFields?has_content>
+        Map<String, PlcValue> fieldValues = new TreeMap<>();
+<#list type.propertyFields as field>
+<#switch field.typeName>
+<#case "array">
+<#case "manualArray">
+
+        {
+            List<PlcValue> plcValues = new ArrayList<>(${field.name}.length);
+            for(${helper.getLanguageTypeNameForField(field)} item : ${field.name}) {
+                <#if helper.isSimpleType(field.type)>
+                plcValues.add(PlcValues.of(item));
+                <#else>
+                plcValues.add(item.toPlcValue());
+                </#if>
+            }
+            fieldValues.put("${field.name}", new PlcList(plcValues));
+        }
+<#break>
+<#case "enum">
+
+        fieldValues.put("${field.name}", new PlcString(${field.name}.name()));
+<#break>
+<#case "manual">
+<#case "simple">
+
+    <#if helper.isSimpleType(field.type)>
+        fieldValues.put("${field.name}", PlcValues.of(${field.name}));
+    <#else>
+        fieldValues.put("${field.name}", ${field.name}.toPlcValue());
+    </#if>
+<#break>
+<#case "optional">
+
+        if(${field.name} != null) {
+            <#if helper.isSimpleType(field.type)>
+            fieldValues.put("${field.name}", PlcValues.of(${field.name}));
+            <#else>
+            fieldValues.put("${field.name}", ${field.name}.toPlcValue());
+            </#if>
+        } else {
+            fieldValues.put("${field.name}", null);
+        }
+<#break>
+<#case "switch">
+
+        PlcStruct superStruct = (PlcStruct) super.toPlcValue();
+        fieldValues.putAll(superStruct.getStruct());
+<#break>
+<#case "virtual">
+    <#if helper.isSimpleType(field.type)>
+
+        fieldValues.put("${field.name}", PlcValues.of(${field.name}));
+    </#if>
+<#break>
+</#switch>
+</#list>
+
+        return new PlcStruct(fieldValues);
+<#else>
+        return null;
+</#if>
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
index c35d155..6d87e7a 100644
--- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
+++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
@@ -22,6 +22,7 @@ import org.apache.plc4x.java.abeth.configuration.AbEthConfiguration;
 import org.apache.plc4x.java.abeth.field.AbEthFieldHandler;
 import org.apache.plc4x.java.abeth.protocol.AbEthProtocolLogic;
 import org.apache.plc4x.java.abeth.readwrite.CIPEncapsulationPacket;
+import org.apache.plc4x.java.abeth.readwrite.io.CIPEncapsulationPacketIO;
 import org.apache.plc4x.java.api.PlcDriver;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
@@ -62,7 +63,7 @@ public class AbEthDriver extends GeneratedDriverBase<CIPEncapsulationPacket> {
 
     @Override
     protected ProtocolStackConfigurer<CIPEncapsulationPacket> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(CIPEncapsulationPacket.class)
+        return SingleProtocolStackConfigurer.builder(CIPEncapsulationPacket.class, CIPEncapsulationPacketIO.class)
             .withProtocol(AbEthProtocolLogic.class)
             .build();
     }
diff --git a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
index f69db93..8cf4208 100644
--- a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
+++ b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
@@ -20,6 +20,7 @@ package org.apache.plc4x.java.knxnetip;
 
 import io.netty.buffer.ByteBuf;
 import org.apache.plc4x.java.knxnetip.configuration.KnxNetIpConfiguration;
+import org.apache.plc4x.java.knxnetip.readwrite.io.KNXNetIPMessageIO;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.knxnetip.field.KnxNetIpFieldHandler;
 import org.apache.plc4x.java.knxnetip.protocol.KnxNetIpProtocolLogic;
@@ -77,7 +78,7 @@ public class KnxNetIpDriver extends GeneratedDriverBase<KNXNetIPMessage> {
 
     @Override
     protected ProtocolStackConfigurer<KNXNetIPMessage> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(KNXNetIPMessage.class)
+        return SingleProtocolStackConfigurer.builder(KNXNetIPMessage.class, KNXNetIPMessageIO.class)
             .withProtocol(KnxNetIpProtocolLogic.class)
             .withPacketSizeEstimator(PacketSizeEstimator.class)
             .build();
diff --git a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
index 7ac7fc4..0a232ac 100644
--- a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
+++ b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
@@ -261,7 +261,7 @@ public class KnxNetIpProtocolLogic extends Plc4xProtocolBase<KNXNetIPMessage> im
 
                             // Parse the payload depending on the type of the group-address.
                             ReadBuffer rawDataReader = new ReadBuffer(payload);
-                            final PlcValue value = KnxDatapointIO.parse(rawDataReader,
+                            final PlcValue value = KnxDatapointIO.staticParse(rawDataReader,
                                 groupAddress.getType().getMainType(), groupAddress.getType().getSubType());
 
                             // Assemble the plc4x return data-structure.
diff --git a/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java b/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
index 5a1c6a1..4f518b0 100644
--- a/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
+++ b/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
@@ -68,7 +68,7 @@ public class IOTest {
         KNXNetIPMessage packet = null;
         for(int i = 0; i < numRunsParse; i++) {
             ReadBuffer rBuf = new ReadBuffer(rData);
-            packet = KNXNetIPMessageIO.parse(rBuf);
+            packet = KNXNetIPMessageIO.staticParse(rBuf);
         }
         long endParsing = System.currentTimeMillis();
 
@@ -80,7 +80,7 @@ public class IOTest {
         byte[] oData = null;
         for(int i = 0; i < numRunsSerialize; i++) {
             WriteBuffer wBuf = new WriteBuffer(packet.getLengthInBytes());
-            KNXNetIPMessageIO.serialize(wBuf, packet);
+            KNXNetIPMessageIO.staticSerialize(wBuf, packet);
             oData = wBuf.getData();
         }
         long endSerializing = System.currentTimeMillis();
diff --git a/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java b/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
index 956a6ed..c676999 100644
--- a/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
+++ b/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
@@ -30,6 +30,13 @@ import java.util.concurrent.TimeUnit;
 
 public class ManualKnxNetIp {
 
+    // Addresses:
+    // */*/10: Temperature
+    // */*/12: Heating
+    // */*/60: Primary Window
+    // */*/64: Second Window
+    // */*/101: Power Line 1
+
     public static void main(String[] args) throws Exception {
         final PlcConnection connection = new PlcDriverManager().getConnection("knxnet-ip://192.168.42.11?knxproj-file-path=/Users/christofer.dutz/Projects/Apache/PLC4X-Documents/KNX/Stettiner%20Str.%2013/StettinerStr-Soll-Ist-Temperatur.knxproj");
         // Make sure we hang up correctly when terminating.
diff --git a/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIpWithEts5.java b/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIpWithEts5.java
index a81ab32..31e604a 100644
--- a/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIpWithEts5.java
+++ b/plc4j/drivers/knxnetip/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIpWithEts5.java
@@ -78,12 +78,12 @@ public class ManualKnxNetIpWithEts5 {
                                 ReadBuffer addressReadBuffer = new ReadBuffer(destinationGroupAddress);
                                 // Decode the group address depending on the project settings.
                                 KNXGroupAddress destinationAddress =
-                                    KNXGroupAddressIO.parse(addressReadBuffer, groupAddressType);
+                                    KNXGroupAddressIO.staticParse(addressReadBuffer, groupAddressType);
                                 final GroupAddress groupAddress = ets5Model.getGroupAddresses().get(destinationAddress);
 
                                 ReadBuffer rawDataReader = new ReadBuffer(payload);
 
-                                final KnxDatapoint datapoint = KnxDatapointIO.parse(rawDataReader, groupAddress.getType().getMainType(), groupAddress.getType().getSubType());
+                                final KnxDatapoint datapoint = KnxDatapointIO.staticParse(rawDataReader, groupAddress.getType().getMainType(), groupAddress.getType().getSubType());
                                 final String jsonDatapoint = datapoint.toString(ToStringStyle.JSON_STYLE);
 
                                 if("Isttemperatur".equals(groupAddress.getName())) {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedProtocolMessageCodec.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedProtocolMessageCodec.java
index 5e1d5ef..1b8e757 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedProtocolMessageCodec.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedProtocolMessageCodec.java
@@ -33,24 +33,12 @@ class GeneratedProtocolMessageCodec<BASE_PACKET_CLASS extends Message> extends G
 
     public GeneratedProtocolMessageCodec(
         Class<BASE_PACKET_CLASS> basePacketClass,
-        Parser<BASE_PACKET_CLASS> parser,
-        Serializer<BASE_PACKET_CLASS> serializer,
+        MessageIO<BASE_PACKET_CLASS, BASE_PACKET_CLASS> messageIO,
         boolean bigEndian,
         Object[] parserArgs,
         ToIntFunction<ByteBuf> packetSizeEstimator,
         Consumer<ByteBuf> corruptPackageRemover) {
-        super(new MessageIO<BASE_PACKET_CLASS, BASE_PACKET_CLASS>() {
-            @Override
-            public BASE_PACKET_CLASS parse(ReadBuffer io, Object... args) {
-                return parser.parse(io, args);
-            }
-
-            @Override
-            public void serialize(WriteBuffer io, BASE_PACKET_CLASS value) {
-                serializer.serialize(io, value);
-            }
-
-        }, basePacketClass, bigEndian, parserArgs);
+        super(messageIO, basePacketClass, bigEndian, parserArgs);
         this.packetSizeEstimator = packetSizeEstimator;
         this.corruptPackageRemover = corruptPackageRemover;
     }
@@ -70,4 +58,5 @@ class GeneratedProtocolMessageCodec<BASE_PACKET_CLASS extends Message> extends G
         }
         this.corruptPackageRemover.accept(byteBuf);
     }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/Parser.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/Parser.java
deleted file mode 100644
index 1eb2115..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/Parser.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.spi.connection;
-
-import org.apache.plc4x.java.spi.generation.Message;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-
-public interface Parser<RESULT extends Message> {
-
-    RESULT parse(ReadBuffer io, Object... args);
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ReflectionBasedIo.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ReflectionBasedIo.java
deleted file mode 100644
index bb4673a..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ReflectionBasedIo.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.spi.connection;
-
-import org.apache.commons.lang3.reflect.MethodUtils;
-import org.apache.plc4x.java.spi.generation.Message;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class ReflectionBasedIo<BASE extends Message> implements Parser<BASE>, Serializer<BASE> {
-
-    private final Method parseMethod;
-    private final Method serializeMethod;
-
-    public ReflectionBasedIo(Class<BASE> clazz) {
-        String className = clazz.getSimpleName() + "IO";
-        String fqcn = clazz.getPackage().getName() + ".io." + className;
-        try {
-            Class<?> ioClass = Class.forName(fqcn);
-            parseMethod = MethodUtils.getMatchingMethod(ioClass, "parse", ReadBuffer.class);
-            serializeMethod = MethodUtils.getMatchingMethod(ioClass, "serialize", WriteBuffer.class, clazz);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException(
-                String.format("Unable to get suitable IO Class for given Message. Expected IO Class '%s' for Class '%s'", clazz.getName(), fqcn));
-        }
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public BASE parse(ReadBuffer io, Object... args) {
-        try {
-            if(args != null) {
-                Object[] mergedArgs = new Object[args.length + 1];
-                mergedArgs[0] = io;
-                System.arraycopy(args, 0, mergedArgs, 1, args.length);
-                return (BASE) parseMethod.invoke(null, mergedArgs);
-            } else {
-                return (BASE) parseMethod.invoke(null, io);
-            }
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new IllegalStateException("Unable to use the parse Method!", e);
-        }
-    }
-
-    @Override
-    public void serialize(WriteBuffer io, BASE message) {
-        try {
-            serializeMethod.invoke(null, io, message);
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new IllegalStateException("Unable to use the serialize Method!", e);
-        }
-    }
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/Serializer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/Serializer.java
deleted file mode 100644
index 7f741e0..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/Serializer.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.spi.connection;
-
-import org.apache.plc4x.java.spi.generation.Message;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-
-public interface Serializer<INPUT extends Message> {
-
-    void serialize(WriteBuffer io, INPUT message);
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java
index 7c25639..3b42fc0 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java
@@ -24,11 +24,13 @@ import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.*;
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelPipeline;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.spi.Plc4xNettyWrapper;
 import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.exceptions.InternalPlcRuntimeException;
 import org.apache.plc4x.java.spi.generation.Message;
+import org.apache.plc4x.java.spi.generation.MessageIO;
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.function.Consumer;
@@ -42,12 +44,13 @@ public class SingleProtocolStackConfigurer<BASE_PACKET_CLASS extends Message> im
     private final Class<BASE_PACKET_CLASS> basePacketClass;
     private boolean bigEndian = true;
     private final Class<? extends Plc4xProtocolBase<BASE_PACKET_CLASS>> protocolClass;
+    private final MessageIO<BASE_PACKET_CLASS, BASE_PACKET_CLASS> protocolIO;
     private final Class<? extends ToIntFunction<ByteBuf>> packetSizeEstimatorClass;
     private final Class<? extends Consumer<ByteBuf>> corruptPacketRemoverClass;
     private final Object[] parserArgs;
 
-    public static <BPC extends Message> SingleProtocolStackBuilder<BPC> builder(Class<BPC> basePacketClass) {
-        return new SingleProtocolStackBuilder<>(basePacketClass);
+    public static <BPC extends Message> SingleProtocolStackBuilder<BPC> builder(Class<BPC> basePacketClass, Class<? extends MessageIO<BPC, BPC>> messageIoClass) {
+        return new SingleProtocolStackBuilder<>(basePacketClass, messageIoClass);
     }
 
     /** Only accessible via Builder */
@@ -55,19 +58,20 @@ public class SingleProtocolStackConfigurer<BASE_PACKET_CLASS extends Message> im
                                   boolean bigEndian,
                                   Object[] parserArgs,
                                   Class<? extends Plc4xProtocolBase<BASE_PACKET_CLASS>> protocol,
+                                  MessageIO<BASE_PACKET_CLASS, BASE_PACKET_CLASS> protocolIO,
                                   Class<? extends ToIntFunction<ByteBuf>> packetSizeEstimatorClass,
                                   Class<? extends Consumer<ByteBuf>> corruptPacketRemoverClass) {
         this.basePacketClass = basePacketClass;
         this.bigEndian = bigEndian;
         this.parserArgs = parserArgs;
         this.protocolClass = protocol;
+        this.protocolIO = protocolIO;
         this.packetSizeEstimatorClass = packetSizeEstimatorClass;
         this.corruptPacketRemoverClass = corruptPacketRemoverClass;
     }
 
     private ChannelHandler getMessageCodec(Configuration configuration) {
-        ReflectionBasedIo<BASE_PACKET_CLASS> io = new ReflectionBasedIo<>(basePacketClass);
-        return new GeneratedProtocolMessageCodec<>(basePacketClass, io, io, bigEndian, parserArgs,
+        return new GeneratedProtocolMessageCodec<>(basePacketClass, protocolIO, bigEndian, parserArgs,
             packetSizeEstimatorClass != null ? configure(configuration, createInstance(packetSizeEstimatorClass)) : null,
             corruptPacketRemoverClass != null ? configure(configuration, createInstance(corruptPacketRemoverClass)) : null);
     }
@@ -98,15 +102,17 @@ public class SingleProtocolStackConfigurer<BASE_PACKET_CLASS extends Message> im
      */
     public static final class SingleProtocolStackBuilder<BASE_PACKET_CLASS extends Message> {
 
-        private Class<BASE_PACKET_CLASS> basePacketClass;
+        private final Class<BASE_PACKET_CLASS> basePacketClass;
+        private final Class<? extends MessageIO<BASE_PACKET_CLASS, BASE_PACKET_CLASS>> messageIoClass;
         private boolean bigEndian = true;
         private Object[] parserArgs;
         private Class<? extends Plc4xProtocolBase<BASE_PACKET_CLASS>> protocol;
         private Class<? extends ToIntFunction<ByteBuf>> packetSizeEstimator;
         private Class<? extends Consumer<ByteBuf>> corruptPacketRemover;
 
-        public SingleProtocolStackBuilder(Class<BASE_PACKET_CLASS> basePacketClass) {
+        public SingleProtocolStackBuilder(Class<BASE_PACKET_CLASS> basePacketClass, Class<? extends MessageIO<BASE_PACKET_CLASS, BASE_PACKET_CLASS>> messageIoClass) {
             this.basePacketClass = basePacketClass;
+            this.messageIoClass = messageIoClass;
         }
 
         public SingleProtocolStackBuilder<BASE_PACKET_CLASS> littleEndian() {
@@ -136,8 +142,13 @@ public class SingleProtocolStackConfigurer<BASE_PACKET_CLASS extends Message> im
 
         public SingleProtocolStackConfigurer<BASE_PACKET_CLASS> build() {
             assert this.protocol != null;
-            return new SingleProtocolStackConfigurer<>(
-                basePacketClass, bigEndian, parserArgs, protocol, packetSizeEstimator, corruptPacketRemover);
+            try {
+                final MessageIO messageIo = messageIoClass.getDeclaredConstructor().newInstance();
+                return new SingleProtocolStackConfigurer<>(
+                    basePacketClass, bigEndian, parserArgs, protocol, messageIo, packetSizeEstimator, corruptPacketRemover);
+            } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
+                throw new PlcRuntimeException("Error initializing MessageIO instance", e);
+            }
         }
 
     }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java
index 25b9f16..54b6df2 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java
@@ -19,8 +19,12 @@
 
 package org.apache.plc4x.java.spi.generation;
 
+import org.apache.plc4x.java.api.value.PlcValue;
+
 public interface Message {
 
     int getLengthInBytes();
 
+    PlcValue toPlcValue();
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/MessageOutput.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/MessageOutput.java
index 26ab0ab..741aebe 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/MessageOutput.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/MessageOutput.java
@@ -20,6 +20,6 @@ package org.apache.plc4x.java.spi.generation;
 
 public interface MessageOutput<SERIALIZER_TYPE> {
 
-    void serialize(WriteBuffer io, SERIALIZER_TYPE value) throws ParseException;
+    void serialize(WriteBuffer io, SERIALIZER_TYPE value, Object... args) throws ParseException;
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/protocol/ProtocolTestsuiteRunner.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/protocol/ProtocolTestsuiteRunner.java
index b260fb5..b2b7922 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/protocol/ProtocolTestsuiteRunner.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/protocol/ProtocolTestsuiteRunner.java
@@ -164,7 +164,7 @@ public class ProtocolTestsuiteRunner {
             Method serializeMethodTmp = null;
             final List<Class<?>> parameterTypes = new LinkedList<>();
             for (Method method : ioClass.getMethods()) {
-                if(method.getName().equals("parse") && Modifier.isStatic(method.getModifiers()) &&
+                if(method.getName().equals("staticParse") && Modifier.isStatic(method.getModifiers()) &&
                     (method.getReturnType() == ioRootClass)) {
                     parseMethodTmp = method;
 
@@ -174,7 +174,7 @@ public class ProtocolTestsuiteRunner {
                         parameterTypes.add(parameterType);
                     }
                 }
-                if(method.getName().equals("serialize") && Modifier.isStatic(method.getModifiers()) &&
+                if(method.getName().equals("staticSerialize") && Modifier.isStatic(method.getModifiers()) &&
                     (method.getParameterTypes()[1] == ioRootClass)) {
                     serializeMethodTmp = method;
                 }
@@ -222,7 +222,7 @@ public class ProtocolTestsuiteRunner {
                 }
 
                 @Override
-                public void serialize(WriteBuffer io, Object value) throws ParseException {
+                public void serialize(WriteBuffer io, Object value, Object... args) throws ParseException {
                     try {
                         serializeMethod.invoke(null, io, value);
                     } catch (IllegalAccessException | InvocationTargetException e) {
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java
index ea6343f..0df0d41 100644
--- a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java
@@ -34,7 +34,7 @@ public class S7Step7Protocol extends GeneratedDriverByteToMessageCodec<TPKTPacke
             @Override
             public TPKTPacket parse(ReadBuffer io, Object... args) throws ParseException {
                 try {
-                    return TPKTPacketIO.parse(io);
+                    return TPKTPacketIO.staticParse(io);
                 } catch (Exception e) {
                     e.printStackTrace();
                     throw new ParseException("Error parsing message", e);
@@ -42,9 +42,9 @@ public class S7Step7Protocol extends GeneratedDriverByteToMessageCodec<TPKTPacke
             }
 
             @Override
-            public void serialize(WriteBuffer io, TPKTPacket value) throws ParseException {
+            public void serialize(WriteBuffer io, TPKTPacket value, Object... args) throws ParseException {
                 try {
-                    TPKTPacketIO.serialize(io, value);
+                    TPKTPacketIO.staticSerialize(io, value);
                 } catch (Exception e) {
                     e.printStackTrace();
                     throw new ParseException("Error serializing message", e);
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java
index 3a5e02f..4cb876c 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java
@@ -24,6 +24,7 @@ import org.apache.plc4x.java.amsads.field.AdsFieldHandler;
 import org.apache.plc4x.java.amsads.protocol.AdsProtocolLogic;
 import org.apache.plc4x.java.amsads.readwrite.AmsNetId;
 import org.apache.plc4x.java.amsads.readwrite.AmsPacket;
+import org.apache.plc4x.java.amsads.readwrite.io.AmsPacketIO;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
@@ -72,7 +73,7 @@ public class AMSADSPlcDriver extends GeneratedDriverBase<AmsPacket> {
 
     @Override
     protected ProtocolStackConfigurer<AmsPacket> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(AmsPacket.class)
+        return SingleProtocolStackConfigurer.builder(AmsPacket.class, AmsPacketIO.class)
             .withProtocol(AdsProtocolLogic.class)
             .build();
     }
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Ads2PayloadProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Ads2PayloadProtocol.java
index 8630498..535e308 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Ads2PayloadProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Ads2PayloadProtocol.java
@@ -62,7 +62,7 @@ public class Ads2PayloadProtocol extends MessageToMessageCodec<ByteBuf, AmsPacke
         }
         WriteBuffer writeBuffer = new WriteBuffer(amsPacket.getLengthInBytes(), true);
         try {
-            AmsPacketIO.serialize(writeBuffer, amsPacket);
+            AmsPacketIO.staticSerialize(writeBuffer, amsPacket);
         } catch (ParseException e) {
             throw new AdsException(invokeId, e);
         }
@@ -83,7 +83,7 @@ public class Ads2PayloadProtocol extends MessageToMessageCodec<ByteBuf, AmsPacke
         ReadBuffer readBuffer = new ReadBuffer(bytes);
         while (readBuffer.getPos() < bytes.length) {
             try {
-                AmsPacket packet = AmsPacketIO.parse(readBuffer);
+                AmsPacket packet = AmsPacketIO.staticParse(readBuffer);
                 out.add(packet);
             } catch (Exception e) {
                 LOGGER.warn("Error decoding package: " + e.getMessage());
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2SerialProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2SerialProtocol.java
index cb04025..11a355b 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2SerialProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2SerialProtocol.java
@@ -58,7 +58,7 @@ public class Payload2SerialProtocol extends MessageToMessageCodec<ByteBuf, ByteB
         byte[] bytes = amsPacket.array();
         AmsPacket amsPacketSer;
         try {
-            amsPacketSer = AmsPacketIO.parse(new ReadBuffer(bytes, true));
+            amsPacketSer = AmsPacketIO.staticParse(new ReadBuffer(bytes, true));
         } catch (ParseException e) {
             throw new AdsException(-1L, e);
         }
@@ -76,7 +76,7 @@ public class Payload2SerialProtocol extends MessageToMessageCodec<ByteBuf, ByteB
 
         WriteBuffer writeBuffer = new WriteBuffer(amsPacketSer.getLengthInBytes(), true);
         try {
-            AmsSerialFrameIO.serialize(writeBuffer, amsSerialFrame);
+            AmsSerialFrameIO.staticSerialize(writeBuffer, amsSerialFrame);
         } catch (ParseException e) {
             throw new AdsException(amsPacketSer.getAmsHeader().getInvokeId(), e);
         }
@@ -96,12 +96,12 @@ public class Payload2SerialProtocol extends MessageToMessageCodec<ByteBuf, ByteB
         ReadBuffer readBuffer = new ReadBuffer(bytes);
         while (readBuffer.getPos() < bytes.length) {
             try {
-                AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.parse(readBuffer);
+                AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.staticParse(readBuffer);
                 AmsPacket amsPacket = amsTCPPacket.getUserdata();
 
                 WriteBuffer writeBuffer = new WriteBuffer(amsPacket.getLengthInBytes(), true);
                 try {
-                    AmsPacketIO.serialize(writeBuffer, amsPacket);
+                    AmsPacketIO.staticSerialize(writeBuffer, amsPacket);
                 } catch (ParseException e) {
                     throw new AdsException(amsPacket.getAmsHeader().getInvokeId(), e);
                 }
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2TcpProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2TcpProtocol.java
index 5e2de80..775c506 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2TcpProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Payload2TcpProtocol.java
@@ -48,14 +48,14 @@ public class Payload2TcpProtocol extends MessageToMessageCodec<ByteBuf, ByteBuf>
         byte[] bytes = amsPacket.array();
         AmsPacket amsPacketSer;
         try {
-            amsPacketSer = AmsPacketIO.parse(new ReadBuffer(bytes, true));
+            amsPacketSer = AmsPacketIO.staticParse(new ReadBuffer(bytes, true));
         } catch (ParseException e) {
             throw new AdsException(-1L, e);
         }
 
         WriteBuffer writeBuffer = new WriteBuffer(amsPacketSer.getLengthInBytes(), true);
         try {
-            AmsTCPPacketIO.serialize(writeBuffer, new AmsTCPPacket(new AmsTcpHeader(amsPacketSer.getLengthInBytes()), amsPacketSer));
+            AmsTCPPacketIO.staticSerialize(writeBuffer, new AmsTCPPacket(new AmsTcpHeader(amsPacketSer.getLengthInBytes()), amsPacketSer));
         } catch (ParseException e) {
             throw new AdsException(amsPacketSer.getAmsHeader().getInvokeId(), e);
         }
@@ -75,12 +75,12 @@ public class Payload2TcpProtocol extends MessageToMessageCodec<ByteBuf, ByteBuf>
         ReadBuffer readBuffer = new ReadBuffer(bytes);
         while (readBuffer.getPos() < bytes.length) {
             try {
-                AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.parse(readBuffer);
+                AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.staticParse(readBuffer);
                 AmsPacket amsPacket = amsTCPPacket.getUserdata();
 
                 WriteBuffer writeBuffer = new WriteBuffer(amsPacket.getLengthInBytes(), true);
                 try {
-                    AmsPacketIO.serialize(writeBuffer, amsPacket);
+                    AmsPacketIO.staticSerialize(writeBuffer, amsPacket);
                 } catch (ParseException e) {
                     throw new AdsException(amsPacket.getAmsHeader().getInvokeId(), e);
                 }
diff --git a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java
index 6a73d85..a0852d6 100644
--- a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java
+++ b/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/PassiveBacNetIpDriver.java
@@ -24,6 +24,7 @@ import org.apache.plc4x.java.bacnetip.configuration.PassiveBacNetIpConfiguration
 import org.apache.plc4x.java.bacnetip.field.BacNetIpFieldHandler;
 import org.apache.plc4x.java.bacnetip.protocol.PassiveBacNetIpProtocolLogic;
 import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
+import org.apache.plc4x.java.bacnetip.readwrite.io.BVLCIO;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
@@ -65,7 +66,7 @@ public class PassiveBacNetIpDriver extends GeneratedDriverBase<BVLC> {
 
     @Override
     protected ProtocolStackConfigurer<BVLC> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(BVLC.class)
+        return SingleProtocolStackConfigurer.builder(BVLC.class, BVLCIO.class)
             .withProtocol(PassiveBacNetIpProtocolLogic.class)
             .withPacketSizeEstimator(ByteLengthEstimator.class)
             .withCorruptPacketRemover(CorruptPackageCleaner.class)
diff --git a/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java b/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java
index ddfd9b0..3a1fa2b 100644
--- a/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java
+++ b/sandbox/test-java-bacnetip-driver/src/test/java/org/apache/plc4x/java/bacnetip/ManualBacNetDecoder.java
@@ -28,7 +28,7 @@ public class ManualBacNetDecoder {
     public static void main(String[] args) throws Exception {
         final byte[] bytes = Hex.decodeHex("810a002b01040205790109011c020000142c000002f93a06b24e09552e44434a00002f096f2e8204002f4f");
         ReadBuffer readBuffer = new ReadBuffer(bytes);
-        final BVLC packet = BVLCIO.parse(readBuffer);
+        final BVLC packet = BVLCIO.staticParse(readBuffer);
         System.out.println(packet);
     }
 
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java
index 30dcd7b..b89dcc1 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java
@@ -23,6 +23,7 @@ import org.apache.plc4x.java.df1.configuration.Df1Configuration;
 import org.apache.plc4x.java.df1.field.Df1FieldHandler;
 import org.apache.plc4x.java.df1.protocol.Df1ProtocolLogic;
 import org.apache.plc4x.java.df1.readwrite.DF1Command;
+import org.apache.plc4x.java.df1.readwrite.io.DF1CommandIO;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
@@ -59,7 +60,7 @@ public class DF1PlcDriver extends GeneratedDriverBase<DF1Command> {
 
     @Override
     protected ProtocolStackConfigurer<DF1Command> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(DF1Command.class)
+        return SingleProtocolStackConfigurer.builder(DF1Command.class, DF1CommandIO.class)
             .withProtocol(Df1ProtocolLogic.class)
             .build();
     }
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java
index 811116d..f8272fc 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java
@@ -61,7 +61,7 @@ public class Df1Protocol extends ByteToMessageCodec<DF1Command> {
 
         // Serialize the message
         WriteBuffer writeBuffer = new WriteBuffer(frame.getLengthInBytes(), false);
-        DF1SymbolIO.serialize(writeBuffer, frame);
+        DF1SymbolIO.staticSerialize(writeBuffer, frame);
         byte[] data = writeBuffer.getData();
 
         // Send the serialized data
@@ -140,7 +140,7 @@ public class Df1Protocol extends ByteToMessageCodec<DF1Command> {
             in.readBytes(data);
             ReadBuffer readBuffer = new ReadBuffer(data, false);
 
-        resp = DF1SymbolIO.parse(readBuffer);
+        resp = DF1SymbolIO.staticParse(readBuffer);
 
 //        } while (readWasSucessfull);
 //        // TODO if unableto read
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
index 53e2fa2..9a2a6f3 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
@@ -24,6 +24,7 @@ import org.apache.plc4x.java.modbus.config.ModbusConfiguration;
 import org.apache.plc4x.java.modbus.field.ModbusFieldHandler;
 import org.apache.plc4x.java.modbus.protocol.ModbusProtocolLogic;
 import org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU;
+import org.apache.plc4x.java.modbus.readwrite.io.ModbusTcpADUIO;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
@@ -72,7 +73,7 @@ public class ModbusDriver extends GeneratedDriverBase<ModbusTcpADU> {
 
     @Override
     protected ProtocolStackConfigurer<ModbusTcpADU> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(ModbusTcpADU.class)
+        return SingleProtocolStackConfigurer.builder(ModbusTcpADU.class, ModbusTcpADUIO.class)
             .withProtocol(ModbusProtocolLogic.class)
             .withPacketSizeEstimator(ByteLengthEstimator.class)
             // Every incoming message is to be treated as a response.
diff --git a/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java b/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java
index 6933c5e..6d569b7 100644
--- a/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java
+++ b/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java
@@ -21,6 +21,7 @@ package org.apache.plc4x.java.s7.readwrite;
 import io.netty.buffer.ByteBuf;
 import org.apache.plc4x.java.api.PlcDriver;
 import org.apache.plc4x.java.s7.readwrite.configuration.S7Configuration;
+import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
 import org.apache.plc4x.java.s7.readwrite.protocol.S7ProtocolLogic;
 import org.apache.plc4x.java.s7.readwrite.field.S7PlcFieldHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
@@ -74,7 +75,7 @@ public class S7Driver extends GeneratedDriverBase<TPKTPacket> {
 
     @Override
     protected ProtocolStackConfigurer<TPKTPacket> getStackConfigurer() {
-        return SingleProtocolStackConfigurer.builder(TPKTPacket.class)
+        return SingleProtocolStackConfigurer.builder(TPKTPacket.class, TPKTPacketIO.class)
             .withProtocol(S7ProtocolLogic.class)
             .withPacketSizeEstimator(ByteLengthEstimator.class)
             .withCorruptPacketRemover(CorruptPackageCleaner.class)
diff --git a/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
index c590c2b..6c80b44 100644
--- a/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
+++ b/sandbox/test-java-s7-driver/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
@@ -520,7 +520,7 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> implements Ha
         try {
             DataTransportSize transportSize = (field.getDataType().getDataProtocolId() == 1) ?
                 DataTransportSize.BIT : DataTransportSize.BYTE_WORD_DWORD;
-            WriteBuffer writeBuffer = DataItemIO.serialize(plcValue, field.getDataType().getDataProtocolId());
+            WriteBuffer writeBuffer = DataItemIO.staticSerialize(plcValue, field.getDataType().getDataProtocolId());
             if(writeBuffer != null) {
                 byte[] data = writeBuffer.getData();
                 return new S7VarPayloadDataItem(DataTransportErrorCode.OK, transportSize, data.length, data);
@@ -534,7 +534,7 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> implements Ha
     private PlcValue parsePlcValue(S7Field field, ByteBuf data) {
         ReadBuffer readBuffer = new ReadBuffer(data.array());
         try {
-            return DataItemIO.parse(readBuffer, field.getDataType().getDataProtocolId());
+            return DataItemIO.staticParse(readBuffer, field.getDataType().getDataProtocolId());
         } catch (ParseException e) {
             logger.warn(String.format("Error parsing field item of type: '%s'", field.getDataType().name()), e);
         }
diff --git a/sandbox/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java b/sandbox/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
index 1c22562..a6d9c34 100644
--- a/sandbox/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
+++ b/sandbox/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
@@ -37,7 +37,7 @@ public class BenchmarkGeneratedS7 {
         TPKTPacket packet = null;
         for(int i = 0; i < numRunsParse; i++) {
             ReadBuffer rBuf = new ReadBuffer(rData);
-            packet = TPKTPacketIO.parse(rBuf);
+            packet = TPKTPacketIO.staticParse(rBuf);
         }
         long endParsing = System.currentTimeMillis();
 
@@ -49,7 +49,7 @@ public class BenchmarkGeneratedS7 {
         byte[] oData = null;
         for(int i = 0; i < numRunsSerialize; i++) {
             WriteBuffer wBuf = new WriteBuffer(packet.getLengthInBytes());
-            TPKTPacketIO.serialize(wBuf, packet);
+            TPKTPacketIO.staticSerialize(wBuf, packet);
             oData = wBuf.getData();
         }
         long endSerializing = System.currentTimeMillis();
diff --git a/sandbox/test-streampipes-plc4x-adapters/pom.xml b/sandbox/test-streampipes-plc4x-adapters/pom.xml
index 6228f96..b613d8e 100644
--- a/sandbox/test-streampipes-plc4x-adapters/pom.xml
+++ b/sandbox/test-streampipes-plc4x-adapters/pom.xml
@@ -79,13 +79,13 @@
     </dependency>
 
     <dependency>
-      <groupId>org.apache.plc4x.sandbox</groupId>
-      <artifactId>test-java-bacnetip-driver</artifactId>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-driver-knxnetip</artifactId>
       <version>0.7.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.apache.plc4x.sandbox</groupId>
-      <artifactId>test-java-knxnetip-driver</artifactId>
+      <artifactId>test-java-bacnetip-driver</artifactId>
       <version>0.7.0-SNAPSHOT</version>
     </dependency>
 
diff --git a/sandbox/test-streampipes-plc4x-processors/pom.xml b/sandbox/test-streampipes-plc4x-processors/pom.xml
index d367e69..9d3b483 100644
--- a/sandbox/test-streampipes-plc4x-processors/pom.xml
+++ b/sandbox/test-streampipes-plc4x-processors/pom.xml
@@ -60,13 +60,8 @@
       <version>0.7.0-SNAPSHOT</version>
     </dependency>
     <dependency>
-      <groupId>org.apache.plc4x.sandbox</groupId>
-      <artifactId>test-java-knxnetip-driver</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.plc4x.sandbox</groupId>
-      <artifactId>test-java-knxnetip-shared</artifactId>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-driver-knxnetip</artifactId>
       <version>0.7.0-SNAPSHOT</version>
     </dependency>
 
diff --git a/sandbox/test-streampipes-plc4x-processors/src/main/java/org/apache/plc4x/java/streampipes/processors/enrich/knxnetip/ets5/Ets5DataEnrichment.java b/sandbox/test-streampipes-plc4x-processors/src/main/java/org/apache/plc4x/java/streampipes/processors/enrich/knxnetip/ets5/Ets5DataEnrichment.java
index bf7714b..0ca55ca 100644
--- a/sandbox/test-streampipes-plc4x-processors/src/main/java/org/apache/plc4x/java/streampipes/processors/enrich/knxnetip/ets5/Ets5DataEnrichment.java
+++ b/sandbox/test-streampipes-plc4x-processors/src/main/java/org/apache/plc4x/java/streampipes/processors/enrich/knxnetip/ets5/Ets5DataEnrichment.java
@@ -63,7 +63,7 @@ public class Ets5DataEnrichment implements EventProcessor<Ets5DataEnrichmentPara
 
             if (groupAddress != null) {
                 // Decode the raw data.
-                final PlcValue plcValue = KnxDatapointIO.parse(rawDataReader, groupAddress.getType().getMainType(), groupAddress.getType().getSubType());
+                final PlcValue plcValue = KnxDatapointIO.staticParse(rawDataReader, groupAddress.getType().getMainType(), groupAddress.getType().getSubType());
 
                 // Serialize the decoded object to json
                 /*final String jsonDatapoint = datapoint.toString(ToStringStyle.JSON_STYLE);