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 2019/08/30 13:40:08 UTC

[plc4x] branch develop updated: - Added an "outputFlavor" element to the plugin configuration which allows selecting different variants of output. - Made sure the generated sources contain the output flavor in the package names to avoid collisions in fat-jar installations.

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 1689aa8  - Added an "outputFlavor" element to the plugin configuration which allows selecting different variants of output. - Made sure the generated sources contain the output flavor in the package names to avoid collisions in fat-jar installations.
1689aa8 is described below

commit 1689aa867af3bb9310774d1158568fbe5cb63ffb
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Fri Aug 30 15:39:42 2019 +0200

    - Added an "outputFlavor" element to the plugin configuration which allows selecting different variants of output.
    - Made sure the generated sources contain the output flavor in the package names to avoid collisions in fat-jar installations.
---
 Dockerfile                                         |   6 +-
 .../freemarker/FreemarkerLanguageOutput.java       |   3 +-
 ...LanguageOutput.java => JavaLanguageOutput.java} |   9 +-
 .../language/java/JavaLanguageTemplateHelper.java  |  10 +-
 .../language/java/JavaPassiveLanguageOutput.java   |  52 ----
 ...x.plugins.codegenerator.language.LanguageOutput |   3 +-
 .../{active-io-template.ftlh => io-template.ftlh}  |   8 +-
 .../templates/java/passive-io-template.ftlh        | 329 ---------------------
 .../resources/templates/java/pojo-template.ftlh    |  14 +-
 .../plugins/codegenerator/language/mspec/MSpec.g4  |   5 +
 .../definitions/DefaultComplexTypeDefinition.java  |  13 +-
 .../mspec/model/fields/DefaultVirtualField.java    |  54 ++++
 .../mspec/parser/MessageFormatListener.java        |  12 +
 sandbox/test-java-ab-eth-driver/pom.xml            |   1 +
 .../plc4x/java/abeth/protocol/AbEthProtocol.java   |   8 +-
 .../java/abeth/protocol/Plc4xAbEthProtocol.java    |   8 +-
 sandbox/test-java-df1-driver/pom.xml               |   1 +
 .../plc4x/java/df1/protocol/Df1Protocol.java       |  11 +-
 .../plc4x/java/df1/protocol/Plc4XDf1Protocol.java  |   6 +-
 .../org/apache/plc4x/java/df1/util/DF1Utils.java   |   5 +-
 .../plc4x/protocol/df1/BenchmarkManualDf1.java     |   7 -
 .../java/org/apache/plc4x/protocol/df1/IOTest.java |   4 +-
 .../src/test/resources/testsuite/Df1Testsuite.xml  |  16 +-
 sandbox/test-java-knxnetip-driver/pom.xml          |   1 +
 .../org/apache/plc4x/java/knxnetip/IOTest.java     |   3 +-
 .../test/resources/testsuite/KNXNetIPTestsuite.xml |  56 ++--
 sandbox/test-java-passive-s7-driver/pom.xml        |   3 +-
 .../s7/protocol/HelloWorldProtocol.java            |   4 +-
 .../javapassive/s7/protocol/PassiveS7Protocol.java |   4 +-
 .../src/test/java/BenchmarkGeneratedPassiveS7.java |   4 +-
 sandbox/test-java-s7-driver/pom.xml                |   1 +
 .../src/test/java/BenchmarkGeneratedS7.java        |   4 +-
 32 files changed, 177 insertions(+), 488 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 2c1e267..26c62ea 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -70,13 +70,13 @@ RUN ./mvnw -P with-java,with-cpp,with-boost,with-dotnet,with-python,with-proxies
 # Get the version of the project and save it in a local file on the container
 RUN ./mvnw org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -DforceStdout -q -pl . > project_version
 
-# Move the file to a place we can reference it from without a version
-RUN PROJECT_VERSION=`cat project_version`; mv plc4j/examples/hello-storage-elasticsearch/target/plc4j-hello-storage-elasticsearch-$PROJECT_VERSION-uber-jar.jar plc4xdemo.jar
-
 ##########################################################################################
 # Build a demo container
 ##########################################################################################
 
+# Move the file to a place we can reference it from without a version
+RUN PROJECT_VERSION=`cat project_version`; mv plc4j/examples/hello-storage-elasticsearch/target/plc4j-hello-storage-elasticsearch-$PROJECT_VERSION-uber-jar.jar plc4xdemo.jar
+
 # Now create an actuall deployment container
 FROM azul/zulu-openjdk:latest
 
diff --git a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java
index 7ae87a7..6ab269e 100644
--- a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java
+++ b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java
@@ -41,7 +41,7 @@ public abstract class FreemarkerLanguageOutput implements LanguageOutput {
     private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerLanguageOutput.class);
 
     @Override
-    public void generate(File outputDir, String languageName, String protocolName, Map<String, ComplexTypeDefinition> types)
+    public void generate(File outputDir, String languageName, String protocolName, String outputFlavor, Map<String, ComplexTypeDefinition> types)
         throws GenerationException {
 
         try {
@@ -62,6 +62,7 @@ public abstract class FreemarkerLanguageOutput implements LanguageOutput {
                 Map<String, Object> typeContext = new HashMap<>();
                 typeContext.put("languageName", languageName);
                 typeContext.put("protocolName", protocolName);
+                typeContext.put("outputFlavor", outputFlavor);
                 typeContext.put("typeName", typeEntry.getKey());
                 typeContext.put("type", typeEntry.getValue());
                 typeContext.put("helper", getHelper(types));
diff --git a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaActiveLanguageOutput.java b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
similarity index 88%
rename from build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaActiveLanguageOutput.java
rename to build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
index 7132f41..58899ba 100644
--- a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaActiveLanguageOutput.java
+++ b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
@@ -27,17 +27,22 @@ import org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefin
 import java.io.*;
 import java.util.*;
 
-public class JavaActiveLanguageOutput extends FreemarkerLanguageOutput {
+public class JavaLanguageOutput extends FreemarkerLanguageOutput {
 
     @Override
     public String getName() {
         return "Java";
     }
 
+    @Override
+    public List<String> supportedOutputFlavors() {
+        return Arrays.asList("read-write", "read-only", "passive");
+    }
+
     protected List<Template> getTemplates(Configuration freemarkerConfiguration) throws IOException {
         return Arrays.asList(
             freemarkerConfiguration.getTemplate("templates/java/pojo-template.ftlh"),
-            freemarkerConfiguration.getTemplate("templates/java/active-io-template.ftlh"));
+            freemarkerConfiguration.getTemplate("templates/java/io-template.ftlh"));
     }
 
     protected FreemarkerLanguageTemplateHelper getHelper(Map<String, ComplexTypeDefinition> types) {
diff --git a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 3dca032..fdf9544 100644
--- a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -46,12 +46,10 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         this.types = types;
     }
 
-    public String languagePackageName(String languageName) {
-        return String.join("", languageName.split("\\-"));
-    }
-
-    public String protocolPackageName(String protocolName) {
-        return String.join("", protocolName.split("\\-"));
+    public String packageName(String protocolName, String languageName, String languageFlavorName) {
+        return "org.apache.plc4x." + String.join("", languageName.split("\\-")) + "." +
+            String.join("", protocolName.split("\\-")) + "." +
+            String.join("", languageFlavorName.split("\\-"));
     }
 
     public String getLanguageTypeNameForField(TypedField field) {
diff --git a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaPassiveLanguageOutput.java b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaPassiveLanguageOutput.java
deleted file mode 100644
index 3273814..0000000
--- a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaPassiveLanguageOutput.java
+++ /dev/null
@@ -1,52 +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.language.java;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import org.apache.plc4x.language.java.JavaLanguageTemplateHelper;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageOutput;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageTemplateHelper;
-import org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-public class JavaPassiveLanguageOutput extends FreemarkerLanguageOutput {
-
-    @Override
-    public String getName() {
-        return "Java-Passive";
-    }
-
-    protected List<Template> getTemplates(Configuration freemarkerConfiguration) throws IOException {
-        return Arrays.asList(
-            freemarkerConfiguration.getTemplate("templates/java/pojo-template.ftlh"),
-            // The passive variant doesn't generate serialize methods in the IO modules.
-            freemarkerConfiguration.getTemplate("templates/java/passive-io-template.ftlh"));
-    }
-
-    protected FreemarkerLanguageTemplateHelper getHelper(Map<String, ComplexTypeDefinition> types) {
-        return new JavaLanguageTemplateHelper(types);
-    }
-
-}
diff --git a/build-utils/language-java/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput b/build-utils/language-java/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
index 7f07221..924bc01 100644
--- a/build-utils/language-java/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
+++ b/build-utils/language-java/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
@@ -16,5 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-org.apache.plc4x.language.java.JavaActiveLanguageOutput
-org.apache.plc4x.language.java.JavaPassiveLanguageOutput
\ No newline at end of file
+org.apache.plc4x.language.java.JavaLanguageOutput
diff --git a/build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
similarity index 97%
rename from build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh
rename to build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
index 3c0a8a1..27d7421 100644
--- a/build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
@@ -16,7 +16,7 @@
   specific language governing permissions and limitations
   under the License.
 -->
-org/apache/plc4x/${helper.languagePackageName(languageName)}/${helper.protocolPackageName(protocolName)}/io/${typeName}IO.java
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${typeName}IO.java
 /*
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -36,10 +36,10 @@ org/apache/plc4x/${helper.languagePackageName(languageName)}/${helper.protocolPa
   under the License.
 */
 
-package org.apache.plc4x.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)}.io;
+package ${helper.packageName(protocolName, languageName, outputFlavor)}.io;
 
-import org.apache.plc4x.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)}.*;
-<#if helper.getComplexTypes(type)?has_content>import org.apache.plc4x.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)}.io.*;</#if>
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
+<#if helper.getComplexTypes(type)?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if>
 import org.apache.plc4x.java.utils.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh
deleted file mode 100644
index 2807bb6..0000000
--- a/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh
+++ /dev/null
@@ -1,329 +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.
--->
-org/apache/plc4x/${helper.languagePackageName(languageName)}/${helper.protocolPackageName(protocolName)}/io/${typeName}IO.java
-/*
-  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.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)}.io;
-
-import org.apache.plc4x.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)}.*;
-<#if helper.getComplexTypes(type)?has_content>import org.apache.plc4x.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)}.io.*;</#if>
-import org.apache.plc4x.java.utils.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.*;
-
-public class ${typeName}IO implements MessageInput<${typeName}<#if helper.isDiscriminatedType(type)>IO.${typeName}Builder</#if>> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(${typeName}IO.class);
-
-<#if helper.getComplexTypes(type)?has_content>
-    // IO Helpers.
-<#list helper.getComplexTypes(type) as complexType>
-    private final ${complexType.name}IO ${complexType.name?uncap_first}IO;
-</#list>
-
-    public ${typeName}IO() {
-<#list helper.getComplexTypes(type) as complexType>
-        ${complexType.name?uncap_first}IO = new ${complexType.name}IO();
-</#list>
-   }
-
-</#if>
-    public ${typeName}<#if helper.isDiscriminatedType(type)>Builder</#if> parse(ReadBuffer io, Object... args) throws ParseException {
-<#if type.parserArguments?has_content>
-<#list type.parserArguments as parserArgument>
-        ${helper.getLanguageTypeNameForSpecType(parserArgument.type)} ${parserArgument.name} = (${helper.getLanguageTypeNameForSpecType(parserArgument.type)}) args[${parserArgument?index}];
-</#list>
-</#if>
-        int startPos = io.getPos();
-        int curPos;
-<#list type.fields as field>
-<#switch field.typeName>
-    <#case "array">
-
-        // Array field (${field.name})
-        <#-- Only update curPos if the length expression uses it -->
-        <#if field.loopExpression.contains("curPos")>
-        curPos = io.getPos() - startPos;
-        </#if>
-        <#-- If this is a count array, we can directly initialize an array with the given size -->
-        <#if helper.isCountArray(field)>
-        // Count array
-        int _${field.name}Count = ${helper.toDeserializationExpression(field.loopExpression, type.parserArguments)};
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}Count];
-        for(int i = 0; i < _${field.name}Count; i++) {
-            ${field.name}[i] = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>;
-        }
-        <#-- In all other cases do we have to work with a list, that is later converted to an array -->
-        <#else>
-            <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-            <#if helper.isLengthArray(field)>
-        // Length array
-        int _${field.name}Length = ${helper.toDeserializationExpression(field.loopExpression, type.parserArguments)};
-        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)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toDeserializationExpression(parserArgument, type.parserArguments)})<#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;
-            </#if>
-        }
-            <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-            <#elseif helper.isTerminatedArray(field)>
-        // Terminated array
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toDeserializationExpression(field.loopExpression, type.parserArguments)}))) {
-            _${field.name}List.add(<#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toDeserializationExpression(parserArgument, type.parserArguments)})<#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;
-            </#if>
-        }
-            </#if>
-            <#--
-                Convert the list into an array. However if the array is of a primitive
-                type we have to iterate over it's elements and explicitly cast them.
-                Otherwise a simple toArray call is fine.
-            -->
-            <#if helper.isSimpleType(field.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}List.size()];
-        for(int i = 0; i < _${field.name}List.size(); i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${field.name}List.get(i);
-        }
-            <#else>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = _${field.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[0]);
-            </#if>
-        </#if>
-        <#break>
-    <#case "checksum">
-
-        // Checksum Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = io.${helper.getReadMethodName(field.type)}(${field.type.size});
-        ${helper.getLanguageTypeNameForField(field)} _${field.name}Ref = (${helper.getLanguageTypeNameForField(field)}) (${helper.toDeserializationExpression(field.checksumExpression, type.parserArguments)});
-        if(${field.name} != _${field.name}Ref) {
-            throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_${field.name}Ref & 0xFFFF, ${field.name} & 0xFFFF));
-        }
-        <#break>
-    <#case "const">
-
-        // Const Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = io.${helper.getReadMethodName(field.type)}(${field.type.size});
-        if(${field.name} != ${typeName}.${field.name?upper_case}) {
-            throw new ParseException("Expected constant value " + ${typeName}.${field.name?upper_case} + " but got " + ${field.name});
-        }
-        <#break>
-    <#case "discriminator">
-
-        // Discriminator Field (${field.name}) (Used as input to a switch field)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = io.${helper.getReadMethodName(field.type)}(${field.type.size});
-    <#break>
-    <#case "implicit">
-
-        // Implicit Field (${field.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = io.${helper.getReadMethodName(field.type)}(${field.type.size});
-        <#break>
-    <#case "manualArray">
-
-        // Manual Array Field (${field.name})
-        <#-- Only update curPos if the length expression uses it -->
-        <#if field.loopExpression.contains("curPos")>
-        curPos = io.getPos() - startPos;
-        </#if>
-        <#-- If this is a count array, we can directly initialize an array with the given size -->
-        <#if helper.isCountArray(field)>
-        // Count array
-        int _${field.name}Count = ${helper.toDeserializationExpression(field.loopExpression, type.parserArguments)};
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}Count];
-        for(int i = 0; i < _${field.name}Count; i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toDeserializationExpression(field.deserializationExpression, type.parserArguments)});
-        }
-        <#-- In all other cases do we have to work with a list, that is later converted to an array -->
-        <#else>
-            <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-            <#if helper.isLengthArray(field)>
-        // Length array
-        int _${field.name}Length = ${helper.toDeserializationExpression(field.loopExpression, type.parserArguments)};
-        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((${helper.getLanguageTypeNameForField(field)}) (${helper.toDeserializationExpression(field.deserializationExpression, type.parserArguments)}));
-            <#-- After parsing, update the current position, but only if it's needed -->
-            <#if field.loopExpression.contains("curPos")>
-            curPos = io.getPos() - startPos;
-            </#if>
-        }
-            <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-            <#elseif helper.isTerminatedArray(field)>
-        // Terminated array
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toDeserializationExpression(field.loopExpression, type.parserArguments)}))) {
-            _${field.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toDeserializationExpression(field.deserializationExpression, type.parserArguments)}));
-
-            <#-- After parsing, update the current position, but only if it's needed -->
-            <#if field.loopExpression.contains("curPos")>
-            curPos = io.getPos() - startPos;
-            </#if>
-        }
-            </#if>
-            <#--
-                Convert the list into an array. However if the array is of a primitive
-                type we have to iterate over it's elements and explicitly cast them.
-                Otherwise a simple toArray call is fine.
-            -->
-            <#if helper.isSimpleType(field.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}List.size()];
-        for(int i = 0; i < _${field.name}List.size(); i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${field.name}List.get(i);
-        }
-            <#else>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = _${field.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[0]);
-            </#if>
-        </#if>
-        <#break>
-    <#case "manual">
-
-        // Manual Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toDeserializationExpression(field.deserializationExpression, type.parserArguments)});
-        <#break>
-    <#case "optional">
-
-        // Optional Field (${field.name}) (Can be skipped, if a given expression evaluates to false)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = null;
-        if(${helper.toDeserializationExpression(field.conditionExpression, type.parserArguments)?no_esc}) {
-            ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io);</#if>;
-        }
-        <#break>
-    <#case "padding">
-
-        // Padding Field (${field.name})
-        boolean _${field.name}NeedsPadding = (boolean) (${helper.toDeserializationExpression(field.paddingCondition, type.parserArguments)});
-        if(_${field.name}NeedsPadding) {
-            // Just read the padding data and ignore it
-            io.${helper.getReadBufferReadMethodCall(field.type)};
-        }
-        <#break>
-    <#case "reserved">
-
-        // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
-        {
-            ${helper.getLanguageTypeNameForField(field)} reserved = io.${helper.getReadBufferReadMethodCall(field.type)};
-            if(reserved != ${field.referenceValue}) {
-                LOGGER.info("Expected constant value " + ${field.referenceValue} + " but got " + reserved + " for reserved field.");
-            }
-        }
-        <#break>
-    <#case "simple">
-
-        // Simple Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toDeserializationExpression(parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
-        <#break>
-    <#case "switch">
-
-        // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
-        ${typeName}Builder builder = null;
-        <#list field.cases as case>
-        if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(field.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) {
-            builder = ${case.name?uncap_first}IO.parse(io<#if case.parserArguments?has_content>, <#list case.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
-        }<#sep> else </#sep>
-        </#list>
-        if (builder == null) {
-            throw new ParseException("Unsupported case for discriminated type");
-        }
-        <#break>
-</#switch>
-</#list>
-
-        // Create the instance
-        <#if helper.isDiscriminatedType(type)>
-        return new ${typeName}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        <#elseif type.abstract>
-        return builder.build(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        <#else>
-        return new ${typeName}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        </#if>
-    }
-
-    private static int COUNT(Object obj) {
-        if(obj.getClass().isArray()) {
-            Object[] arr = (Object[]) obj;
-            return arr.length;
-        } else if(obj instanceof Collection) {
-            Collection col = (Collection) obj;
-            return col.size();
-        }
-        throw new RuntimeException("Unable to count object of type " + obj.getClass().getName());
-    }
-
-    private static <T> T CAST(Object obj, Class<T> clazz) {
-        try {
-            return clazz.cast(obj);
-        } catch(ClassCastException e) {
-            throw new RuntimeException("Unable to cast object of type " + obj.getClass().getName() + " to " + clazz.getName());
-        }
-    }
-
-<#if type.abstract>
-    public static interface ${typeName}Builder {
-        ${typeName} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>);
-    }
-
-</#if>
-<#if helper.isDiscriminatedType(type)>
-    public static class ${typeName}Builder implements ${type.parentType.name}IO.${type.parentType.name}Builder {
-        <#if type.propertyFields?has_content>
-        <#list type.propertyFields as field>
-        private final ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name};
-        </#list>
-        </#if>
-
-        public ${typeName}Builder(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
-            <#list type.propertyFields as field>
-            this.${field.name} = ${field.name};
-            </#list>
-        }
-
-        public ${typeName} build(<#list type.parentType.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
-            return new ${typeName}(<#list type.getAllPropertyFields() as field>${field.name}<#sep>, </#sep></#list>);
-        }
-    }
-
-</#if>
-}
\ No newline at end of file
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 27d52d5..b3fbaf8 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
@@ -16,7 +16,7 @@
   specific language governing permissions and limitations
   under the License.
 -->
-org/apache/plc4x/${helper.languagePackageName(languageName)}/${helper.protocolPackageName(protocolName)}/${typeName}.java
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${typeName}.java
 /*
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -36,7 +36,7 @@ org/apache/plc4x/${helper.languagePackageName(languageName)}/${helper.protocolPa
   under the License.
 */
 
-package org.apache.plc4x.${helper.languagePackageName(languageName)}.${helper.protocolPackageName(protocolName)};
+package ${helper.packageName(protocolName, languageName, outputFlavor)};
 
 import com.fasterxml.jackson.annotation.*;
 import org.apache.plc4x.java.utils.Message;
@@ -99,6 +99,12 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
     }
 
 </#list>
+<#list type.virtualFields as field>
+    public ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.name?cap_first}() {
+        return (${helper.getLanguageTypeNameForField(field)}) (${helper.toDeserializationExpression(field.valueExpression)});;
+    }
+
+</#list>
     @Override
     @JsonIgnore
     public int getLengthInBytes() {
@@ -182,6 +188,10 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 
         // Length of sub-type elements will be added by sub-type...
         <#break>
+    <#case "virtual">
+
+        // A virtual field doesn't have any in- or output.
+        <#break>
 </#switch>
 </#list>
 
diff --git a/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 b/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
index b049b80..826191d 100644
--- a/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
+++ b/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
@@ -50,6 +50,7 @@ field
  | reservedField
  | simpleField
  | typeSwitchField
+ | virtualField
  ;
 
 arrayField
@@ -100,6 +101,10 @@ typeSwitchField
  : 'typeSwitch' discriminators=multipleExpressions caseStatement*
  ;
 
+virtualField
+ : 'virtual' type=dataType name=idExpression valueExpression=expression
+ ;
+
 
 typeReference
  : complexTypeReference=IDENTIFIER
diff --git a/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java b/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java
index 7d38171..905088d 100644
--- a/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java
+++ b/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java
@@ -21,10 +21,7 @@ package org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions;
 
 import org.apache.plc4x.plugins.codegenerator.types.definitions.Argument;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition;
-import org.apache.plc4x.plugins.codegenerator.types.fields.ConstField;
-import org.apache.plc4x.plugins.codegenerator.types.fields.Field;
-import org.apache.plc4x.plugins.codegenerator.types.fields.PropertyField;
-import org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField;
+import org.apache.plc4x.plugins.codegenerator.types.fields.*;
 
 import java.util.Collections;
 import java.util.LinkedList;
@@ -64,7 +61,13 @@ public class DefaultComplexTypeDefinition extends DefaultTypeDefinition implemen
 
     @Override
     public List<PropertyField> getPropertyFields() {
-        return fields.stream().filter(field -> ((field instanceof PropertyField) && !(field instanceof ConstField))).map(field -> (PropertyField) field)
+        return fields.stream().filter(field -> ((field instanceof PropertyField) && !(field instanceof ConstField) && !(field instanceof VirtualField))).map(field -> (PropertyField) field)
+            .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<VirtualField> getVirtualFields() {
+        return fields.stream().filter(field -> (field instanceof VirtualField)).map(field -> (VirtualField) field)
             .collect(Collectors.toList());
     }
 
diff --git a/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java b/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java
new file mode 100644
index 0000000..249170b
--- /dev/null
+++ b/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java
@@ -0,0 +1,54 @@
+/*
+ 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.plugins.codegenerator.language.mspec.model.fields;
+
+import org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField;
+import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
+import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
+
+public class DefaultVirtualField implements VirtualField {
+
+    private final TypeReference type;
+    private final String name;
+    private final Term valueExpression;
+
+    public DefaultVirtualField(TypeReference type, String name, Term valueExpression) {
+        this.type = type;
+        this.name = name;
+        this.valueExpression = valueExpression;
+    }
+
+    public TypeReference getType() {
+        return type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Term getValueExpression() {
+        return valueExpression;
+    }
+
+    public Term[] getParams() {
+        return new Term[0];
+    }
+
+}
diff --git a/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java b/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
index 74eafac..cdaea00 100644
--- a/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
+++ b/build-utils/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
@@ -251,6 +251,18 @@ public class MessageFormatListener extends MSpecBaseListener {
     }
 
     @Override
+    public void enterVirtualField(MSpecParser.VirtualFieldContext ctx) {
+        SimpleTypeReference type = getSimpleTypeReference(ctx.type);
+        String name = ctx.name.id.getText();
+        String valueExpressionString = ctx.valueExpression.expr.getText();
+        Term valueExpression = getExpressionTerm(valueExpressionString);
+        Field field = new DefaultVirtualField(type, name, valueExpression);
+        if(parserContexts.peek() != null) {
+            parserContexts.peek().add(field);
+        }
+    }
+
+    @Override
     public void enterCaseStatement(MSpecParser.CaseStatementContext ctx) {
         List<Field> parserContext = new LinkedList<>();
         parserContexts.push(parserContext);
diff --git a/sandbox/test-java-ab-eth-driver/pom.xml b/sandbox/test-java-ab-eth-driver/pom.xml
index 4750ea2..895b791 100644
--- a/sandbox/test-java-ab-eth-driver/pom.xml
+++ b/sandbox/test-java-ab-eth-driver/pom.xml
@@ -47,6 +47,7 @@
             <configuration>
               <protocolName>ab-eth</protocolName>
               <languageName>java</languageName>
+              <outputFlavor>read-write</outputFlavor>
             </configuration>
           </execution>
         </executions>
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java
index c45d9e6..e8ad9e0 100644
--- a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java
@@ -20,13 +20,9 @@ package org.apache.plc4x.java.abeth.protocol;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
-import org.apache.plc4x.java.abeth.CIPEncapsulationConnectionRequest;
-import org.apache.plc4x.java.abeth.CIPEncapsulationConnectionResponse;
-import org.apache.plc4x.java.abeth.CIPEncapsulationPacket;
-import org.apache.plc4x.java.abeth.io.CIPEncapsulationPacketIO;
+import org.apache.plc4x.java.abeth.readwrite.CIPEncapsulationPacket;
+import org.apache.plc4x.java.abeth.readwrite.io.CIPEncapsulationPacketIO;
 import org.apache.plc4x.java.base.PlcByteToMessageCodec;
-import org.apache.plc4x.java.base.events.ConnectEvent;
-import org.apache.plc4x.java.base.events.ConnectedEvent;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.WriteBuffer;
 import org.slf4j.Logger;
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
index 85eee25..d0db465 100644
--- a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
@@ -19,14 +19,12 @@ under the License.
 package org.apache.plc4x.java.abeth.protocol;
 
 import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.plc4x.java.abeth.*;
 import org.apache.plc4x.java.abeth.model.AbEthField;
+import org.apache.plc4x.java.abeth.readwrite.*;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcRequest;
 import org.apache.plc4x.java.api.messages.PlcResponse;
@@ -44,14 +42,10 @@ import org.apache.plc4x.java.base.messages.items.DefaultShortFieldItem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.lang.reflect.Array;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 
 public class Plc4xAbEthProtocol extends PlcMessageToMessageCodec<CIPEncapsulationPacket, PlcRequestContainer> {
 
diff --git a/sandbox/test-java-df1-driver/pom.xml b/sandbox/test-java-df1-driver/pom.xml
index 0dc1330..76c0b15 100644
--- a/sandbox/test-java-df1-driver/pom.xml
+++ b/sandbox/test-java-df1-driver/pom.xml
@@ -47,6 +47,7 @@
             <configuration>
               <protocolName>df1</protocolName>
               <languageName>java</languageName>
+              <outputFlavor>read-write</outputFlavor>
             </configuration>
           </execution>
         </executions>
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 820bfc4..cd21883 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
@@ -23,19 +23,16 @@ import io.netty.buffer.ByteBufUtil;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
 import org.apache.plc4x.java.base.PlcByteToMessageCodec;
-import org.apache.plc4x.java.df1.DF1Command;
-import org.apache.plc4x.java.df1.DF1Symbol;
-import org.apache.plc4x.java.df1.DF1SymbolMessageFrame;
-import org.apache.plc4x.java.df1.DF1UnprotectedReadRequest;
-import org.apache.plc4x.java.df1.io.DF1SymbolIO;
+import org.apache.plc4x.java.df1.readwrite.DF1Command;
+import org.apache.plc4x.java.df1.readwrite.DF1Symbol;
+import org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame;
+import org.apache.plc4x.java.df1.readwrite.io.DF1SymbolIO;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.WriteBuffer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 public class Df1Protocol extends PlcByteToMessageCodec<DF1Command> {
 
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java
index dd5e711..d169dca 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java
@@ -18,12 +18,9 @@
  */
 package org.apache.plc4x.java.df1.protocol;
 
-import com.github.jinahya.bit.io.DefaultBitInput;
-import com.github.jinahya.bit.io.DefaultBitOutput;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.commons.lang3.NotImplementedException;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcRequest;
 import org.apache.plc4x.java.api.messages.PlcResponse;
@@ -35,10 +32,9 @@ import org.apache.plc4x.java.base.messages.DefaultPlcReadResponse;
 import org.apache.plc4x.java.base.messages.InternalPlcReadRequest;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
 import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
-import org.apache.plc4x.java.base.messages.items.DefaultFloatFieldItem;
 import org.apache.plc4x.java.base.messages.items.DefaultIntegerFieldItem;
 import org.apache.plc4x.java.df1.*;
-import org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields.DefaultArrayField;
+import org.apache.plc4x.java.df1.readwrite.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
index d335886..df5f009 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
@@ -18,8 +18,9 @@
  */
 package org.apache.plc4x.java.df1.util;
 
-import org.apache.commons.io.filefilter.FalseFileFilter;
-import org.apache.plc4x.java.df1.*;
+import org.apache.plc4x.java.df1.readwrite.DF1Command;
+import org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadRequest;
+import org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadResponse;
 import org.apache.plc4x.java.utils.ParseException;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.WriteBuffer;
diff --git a/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
index dc17473..7e4141b 100644
--- a/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
+++ b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
@@ -20,13 +20,6 @@
 package org.apache.plc4x.protocol.df1;
 
 import com.fazecast.jSerialComm.SerialPort;
-import org.apache.plc4x.java.df1.DF1Command;
-import org.apache.plc4x.java.df1.DF1Symbol;
-import org.apache.plc4x.java.df1.io.DF1SymbolIO;
-import org.apache.plc4x.java.utils.ReadBuffer;
-
-//import org.apache.plc4x.java.df1.TPKTPacket;
-//import org.apache.plc4x.java.df1.io.TPKTPacketIO;
 
 public class BenchmarkManualDf1 {
 
diff --git a/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/IOTest.java b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/IOTest.java
index b79ef43..6179b7f 100644
--- a/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/IOTest.java
+++ b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/IOTest.java
@@ -22,8 +22,8 @@ package org.apache.plc4x.protocol.df1;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import org.apache.commons.codec.binary.Hex;
-import org.apache.plc4x.java.df1.DF1Symbol;
-import org.apache.plc4x.java.df1.io.DF1SymbolIO;
+import org.apache.plc4x.java.df1.readwrite.DF1Symbol;
+import org.apache.plc4x.java.df1.readwrite.io.DF1SymbolIO;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.junit.jupiter.api.Test;
 
diff --git a/sandbox/test-java-df1-driver/src/test/resources/testsuite/Df1Testsuite.xml b/sandbox/test-java-df1-driver/src/test/resources/testsuite/Df1Testsuite.xml
index 0cf6434..27dcbec 100644
--- a/sandbox/test-java-df1-driver/src/test/resources/testsuite/Df1Testsuite.xml
+++ b/sandbox/test-java-df1-driver/src/test/resources/testsuite/Df1Testsuite.xml
@@ -27,10 +27,10 @@
     <raw>10020900010001001100021003546F</raw>
     <root-type>DF1Symbol</root-type>
     <xml>
-      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.DF1SymbolMessageFrame">
+      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame">
         <destinationAddress>9</destinationAddress>
         <sourceAddress>0</sourceAddress>
-        <command className="org.apache.plc4x.java.df1.DF1UnprotectedReadRequest">
+        <command className="org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadRequest">
           <status>0</status>
           <transactionCounter>1</transactionCounter>
           <address>17</address>
@@ -45,10 +45,10 @@
     <raw>10020A0941000100FFFF1003DFB9</raw>
     <root-type>DF1Symbol</root-type>
     <xml>
-      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.DF1SymbolMessageFrame">
+      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame">
         <destinationAddress>10</destinationAddress>
         <sourceAddress>9</sourceAddress>
-        <command className="org.apache.plc4x.java.df1.DF1UnprotectedReadResponse">
+        <command className="org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadResponse">
           <status>0</status>
           <transactionCounter>1</transactionCounter>
           <data>
@@ -65,10 +65,10 @@
     <raw>10020A09410001001010FF1003BAAD</raw>
     <root-type>DF1Symbol</root-type>
     <xml>
-      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.DF1SymbolMessageFrame">
+      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame">
         <destinationAddress>10</destinationAddress>
         <sourceAddress>9</sourceAddress>
-        <command className="org.apache.plc4x.java.df1.DF1UnprotectedReadResponse">
+        <command className="org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadResponse">
           <status>0</status>
           <transactionCounter>1</transactionCounter>
           <data>
@@ -85,7 +85,7 @@
     <raw>1006</raw>
     <root-type>DF1Symbol</root-type>
     <xml>
-      <DF1SymbolMessageFrameACK className="org.apache.plc4x.java.df1.DF1SymbolMessageFrameACK"/>
+      <DF1SymbolMessageFrameACK className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrameACK"/>
     </xml>
   </testcase>
 
@@ -94,7 +94,7 @@
     <raw>1015</raw>
     <root-type>DF1Symbol</root-type>
     <xml>
-      <DF1SymbolMessageFrameNAK className="org.apache.plc4x.java.df1.DF1SymbolMessageFrameNAK"/>
+      <DF1SymbolMessageFrameNAK className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrameNAK"/>
     </xml>
   </testcase>
 
diff --git a/sandbox/test-java-knxnetip-driver/pom.xml b/sandbox/test-java-knxnetip-driver/pom.xml
index ebb071a..f477b42 100644
--- a/sandbox/test-java-knxnetip-driver/pom.xml
+++ b/sandbox/test-java-knxnetip-driver/pom.xml
@@ -47,6 +47,7 @@
             <configuration>
               <protocolName>knxnetip</protocolName>
               <languageName>java</languageName>
+              <outputFlavor>read-write</outputFlavor>
             </configuration>
           </execution>
         </executions>
diff --git a/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java b/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
index e43ecfa..711c1ae 100644
--- a/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
+++ b/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
@@ -22,7 +22,8 @@ package org.apache.plc4x.java.knxnetip;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import org.apache.commons.codec.binary.Hex;
-import org.apache.plc4x.java.knxnetip.io.KNXNetIPMessageIO;
+import org.apache.plc4x.java.knxnetip.readwrite.KNXNetIPMessage;
+import org.apache.plc4x.java.knxnetip.readwrite.io.KNXNetIPMessageIO;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.WriteBuffer;
 import org.junit.jupiter.api.Test;
diff --git a/sandbox/test-java-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml b/sandbox/test-java-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml
index ffe965b..10fb85c 100644
--- a/sandbox/test-java-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml
+++ b/sandbox/test-java-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml
@@ -26,7 +26,7 @@
     <raw>06100201000e0801c0a82a46ef8e</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <SearchRequest className="org.apache.plc4x.java.knxnetip.SearchRequest">
+      <SearchRequest className="org.apache.plc4x.java.knxnetip.readwrite.SearchRequest">
         <hpaiIDiscoveryEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
           <ipAddress>
@@ -48,7 +48,7 @@
     <raw>06100202004c0801c0a82a0b0e5736010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <SearchResponse className="org.apache.plc4x.java.knxnetip.SearchResponse">
+      <SearchResponse className="org.apache.plc4x.java.knxnetip.readwrite.SearchResponse">
         <hpaiControlEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
           <ipAddress>
@@ -138,13 +138,13 @@
         <dibSuppSvcFamilies>
           <descriptionType>2</descriptionType>
           <serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.KnxNetIpCore">
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
               <version>1</version>
             </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.KnxNetIpDeviceManagement">
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
               <version>1</version>
             </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.KnxNetIpTunneling">
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
               <version>1</version>
             </serviceIds>
           </serviceIds>
@@ -158,7 +158,7 @@
     <raw>06100203000e0801000000000000</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <DescriptionRequest className="org.apache.plc4x.java.knxnetip.DescriptionRequest">
+      <DescriptionRequest className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionRequest">
         <hpaiControlEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
           <ipAddress>
@@ -180,7 +180,7 @@
     <raw>06100204004436010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <DescriptionResponse className="org.apache.plc4x.java.knxnetip.DescriptionResponse">
+      <DescriptionResponse className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionResponse">
         <dibDeviceInfo>
           <descriptionType>1</descriptionType>
           <knxMedium>2</knxMedium>
@@ -258,13 +258,13 @@
         <dibSuppSvcFamilies>
           <descriptionType>2</descriptionType>
           <serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.KnxNetIpCore">
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
               <version>1</version>
             </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.KnxNetIpDeviceManagement">
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
               <version>1</version>
             </serviceIds>
-            <serviceIds className="org.apache.plc4x.java.knxnetip.KnxNetIpTunneling">
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
               <version>1</version>
             </serviceIds>
           </serviceIds>
@@ -278,7 +278,7 @@
     <raw>06100205001a0801c0a82a46f4310801c0a82a46f43204040200</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.ConnectionRequest">
+      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
         <hpaiDiscoveryEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
           <ipAddress>
@@ -303,7 +303,7 @@
           </ipAddress>
           <ipPort>62514</ipPort>
         </hpaiDataEndpoint>
-        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.ConnectionRequestInformationTunnelConnection">
+        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationTunnelConnection">
           <knxLayer>2</knxLayer>
         </connectionRequestInformation>
       </ConnectionRequest>
@@ -315,7 +315,7 @@
     <raw>06100206001466000801c0a82a0b0e5704041101</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <ConnectionResponse className="org.apache.plc4x.java.knxnetip.ConnectionResponse">
+      <ConnectionResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponse">
         <communicationChannelId>102</communicationChannelId>
         <status>0</status>
         <hpaiDataEndpoint>
@@ -330,7 +330,7 @@
           </ipAddress>
           <ipPort>3671</ipPort>
         </hpaiDataEndpoint>
-        <connectionResponseDataBlock className="org.apache.plc4x.java.knxnetip.ConnectionResponseDataBlockTunnelConnection">
+        <connectionResponseDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponseDataBlockTunnelConnection">
           <knxAddress>
             <mainGroup>1</mainGroup>
             <middleGroup>1</middleGroup>
@@ -346,7 +346,7 @@
     <raw>06100207001066000801c0a82a46f431</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <ConnectionStateRequest className="org.apache.plc4x.java.knxnetip.ConnectionStateRequest">
+      <ConnectionStateRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateRequest">
         <communicationChannelId>102</communicationChannelId>
         <hpaiControlEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
@@ -369,7 +369,7 @@
     <raw>0610020800086600</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <ConnectionStateResponse className="org.apache.plc4x.java.knxnetip.ConnectionStateResponse">
+      <ConnectionStateResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateResponse">
         <communicationChannelId>102</communicationChannelId>
         <status>0</status>
       </ConnectionStateResponse>
@@ -381,12 +381,12 @@
     <raw>06100310001104670000fc000001531001</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <DeviceConfigurationRequest className="org.apache.plc4x.java.knxnetip.DeviceConfigurationRequest">
+      <DeviceConfigurationRequest className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationRequest">
         <deviceConfigurationRequestDataBlock>
           <communicationChannelId>103</communicationChannelId>
           <sequenceCounter>0</sequenceCounter>
         </deviceConfigurationRequestDataBlock>
-        <cemi className="org.apache.plc4x.java.knxnetip.CEMIMPropReadReq">
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIMPropReadReq">
           <interfaceObjectType>0</interfaceObjectType>
           <objectInstance>1</objectInstance>
           <propertyId>83</propertyId>
@@ -402,7 +402,7 @@
     <raw>06100311000a04670000</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <DeviceConfigurationAck className="org.apache.plc4x.java.knxnetip.DeviceConfigurationAck">
+      <DeviceConfigurationAck className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationAck">
         <deviceConfigurationAckDataBlock>
           <communicationChannelId>103</communicationChannelId>
           <sequenceCounter>0</sequenceCounter>
@@ -417,7 +417,7 @@
     <raw>06100209001067000801c0a82a46f431</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <DisconnectRequest className="org.apache.plc4x.java.knxnetip.DisconnectRequest">
+      <DisconnectRequest className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectRequest">
         <communicationChannelId>103</communicationChannelId>
         <hpaiControlEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
@@ -440,7 +440,7 @@
     <raw>0610020a00086600</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <DisconnectResponse className="org.apache.plc4x.java.knxnetip.DisconnectResponse">
+      <DisconnectResponse className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectResponse">
         <communicationChannelId>102</communicationChannelId>
         <status>0</status>
       </DisconnectResponse>
@@ -452,15 +452,15 @@
     <raw>06100420001c046b00002b0703010504024502bc360a1e0ce100810d</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.TunnelingRequest">
+      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequest">
         <tunnelingRequestDataBlock>
           <communicationChannelId>107</communicationChannelId>
           <sequenceCounter>0</sequenceCounter>
         </tunnelingRequestDataBlock>
-        <cemi className="org.apache.plc4x.java.knxnetip.CEMILBusmonInd">
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMILBusmonInd">
           <additionalInformationLength>7</additionalInformationLength>
           <additionalInformation>
-            <additionalInformation className="org.apache.plc4x.java.knxnetip.CEMIAdditionalInformationBusmonitorInfo">
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
               <frameErrorFlag>false</frameErrorFlag>
               <bitErrorFlag>false</bitErrorFlag>
               <parityErrorFlag>false</parityErrorFlag>
@@ -468,7 +468,7 @@
               <lostFlag>false</lostFlag>
               <sequenceNumber>5</sequenceNumber>
             </additionalInformation>
-            <additionalInformation className="org.apache.plc4x.java.knxnetip.CEMIAdditionalInformationRelativeTimestamp">
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationRelativeTimestamp">
               <relativeTimestamp>
                 <timestamp>17666</timestamp>
               </relativeTimestamp>
@@ -496,7 +496,7 @@
     <raw>06100421000a046b0000</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <TunnelingResponse className="org.apache.plc4x.java.knxnetip.TunnelingResponse">
+      <TunnelingResponse className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingResponse">
         <tunnelingResponseDataBlock>
           <communicationChannelId>107</communicationChannelId>
           <sequenceCounter>0</sequenceCounter>
@@ -511,7 +511,7 @@
     <raw>0610020500180801c0a82a46c4090801c0a82a46c40a0203</raw>
     <root-type>KNXNetIPMessage</root-type>
     <xml>
-      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.ConnectionRequest">
+      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
         <hpaiDiscoveryEndpoint>
           <hostProtocolCode>1</hostProtocolCode>
           <ipAddress>
@@ -536,7 +536,7 @@
           </ipAddress>
           <ipPort>50186</ipPort>
         </hpaiDataEndpoint>
-        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.ConnectionRequestInformationDeviceManagement"/>
+        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationDeviceManagement"/>
       </ConnectionRequest>
     </xml>
   </testcase>
diff --git a/sandbox/test-java-passive-s7-driver/pom.xml b/sandbox/test-java-passive-s7-driver/pom.xml
index 4720867..b872d53 100644
--- a/sandbox/test-java-passive-s7-driver/pom.xml
+++ b/sandbox/test-java-passive-s7-driver/pom.xml
@@ -46,7 +46,8 @@
             </goals>
             <configuration>
               <protocolName>s7</protocolName>
-              <languageName>java-passive</languageName>
+              <languageName>java</languageName>
+              <outputFlavor>passive</outputFlavor>
             </configuration>
           </execution>
         </executions>
diff --git a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java
index bec33bd..8f6f455 100644
--- a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java
+++ b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java
@@ -21,8 +21,8 @@ package org.apache.plc4x.javapassive.s7.protocol;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
-import org.apache.plc4x.javapassive.s7.S7Message;
-import org.apache.plc4x.javapassive.s7.TPKTPacket;
+import org.apache.plc4x.java.s7.passive.S7Message;
+import org.apache.plc4x.java.s7.passive.TPKTPacket;
 
 import java.util.List;
 
diff --git a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java
index a758e71..038f84a 100644
--- a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java
+++ b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java
@@ -21,9 +21,9 @@ package org.apache.plc4x.javapassive.s7.protocol;
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.plc4x.java.base.PlcByteToMessageCodec;
+import org.apache.plc4x.java.s7.passive.TPKTPacket;
+import org.apache.plc4x.java.s7.passive.io.TPKTPacketIO;
 import org.apache.plc4x.java.utils.ReadBuffer;
-import org.apache.plc4x.javapassive.s7.TPKTPacket;
-import org.apache.plc4x.javapassive.s7.io.TPKTPacketIO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/sandbox/test-java-passive-s7-driver/src/test/java/BenchmarkGeneratedPassiveS7.java b/sandbox/test-java-passive-s7-driver/src/test/java/BenchmarkGeneratedPassiveS7.java
index 48207b7..a9ecd7a 100644
--- a/sandbox/test-java-passive-s7-driver/src/test/java/BenchmarkGeneratedPassiveS7.java
+++ b/sandbox/test-java-passive-s7-driver/src/test/java/BenchmarkGeneratedPassiveS7.java
@@ -18,8 +18,8 @@
  */
 
 import org.apache.commons.codec.binary.Hex;
-import org.apache.plc4x.javapassive.s7.TPKTPacket;
-import org.apache.plc4x.javapassive.s7.io.TPKTPacketIO;
+import org.apache.plc4x.java.s7.passive.TPKTPacket;
+import org.apache.plc4x.java.s7.passive.io.TPKTPacketIO;
 import org.apache.plc4x.java.utils.ReadBuffer;
 
 public class BenchmarkGeneratedPassiveS7 {
diff --git a/sandbox/test-java-s7-driver/pom.xml b/sandbox/test-java-s7-driver/pom.xml
index bd9285d..f5985b6 100644
--- a/sandbox/test-java-s7-driver/pom.xml
+++ b/sandbox/test-java-s7-driver/pom.xml
@@ -47,6 +47,7 @@
             <configuration>
               <protocolName>s7</protocolName>
               <languageName>java</languageName>
+              <outputFlavor>read-write</outputFlavor>
             </configuration>
           </execution>
         </executions>
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 e231fe9..67cbe2f 100644
--- a/sandbox/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
+++ b/sandbox/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
@@ -18,8 +18,8 @@
  */
 
 import org.apache.commons.codec.binary.Hex;
-import org.apache.plc4x.java.s7.TPKTPacket;
-import org.apache.plc4x.java.s7.io.TPKTPacketIO;
+import org.apache.plc4x.java.s7.readwrite.TPKTPacket;
+import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.WriteBuffer;