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 2021/10/13 17:42:53 UTC

[plc4x] branch feature/mspec-ng updated: - Continued porting more types to the new code-generation

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

cdutz pushed a commit to branch feature/mspec-ng
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/mspec-ng by this push:
     new 183b843  - Continued porting more types to the new code-generation
183b843 is described below

commit 183b8435e2a32adfbdd9e5bb2ab26a0c8d1965f2
Author: cdutz <ch...@c-ware.de>
AuthorDate: Wed Oct 13 19:42:17 2021 +0200

    - Continued porting more types to the new code-generation
---
 .../FreemarkerLanguageTemplateHelper.java          |   3 +
 code-generation/language-c/pom.xml                 |   7 +
 code-generation/language-go/pom.xml                |  40 +-
 .../plc4x/language/java/JavaLanguageOutput.java    | 103 ---
 .../language/java/JavaLanguageTemplateHelper.java  | 984 ---------------------
 .../resources/templates/java/io-template.java.ftlh | 942 --------------------
 .../pom.xml                                        |  11 +-
 .../plc4x/language/java/JavaLanguageOutput.java    |   0
 .../language/java/JavaLanguageTemplateHelper.java  |   0
 ...x.plugins.codegenerator.language.LanguageOutput |   0
 .../templates/java/data-io-template.java.ftlh      |   0
 .../java/enum-package-info-template.java.ftlh      |   0
 .../templates/java/enum-template.java.ftlh         |   0
 .../resources/templates/java/io-template.java.ftlh |   0
 .../templates/java/pojo-template.java.ftlh         |   0
 .../src/test/resources/integration-test/pom.xml    |   4 +-
 .../src/test/resources/settings.xml                |   0
 code-generation/language-java/pom.xml              |   7 +
 .../plc4x/language/java/JavaLanguageOutput.java    |  19 +-
 .../language/java/JavaLanguageTemplateHelper.java  |  72 +-
 .../resources/templates/java/io-template.java.ftlh |  86 +-
 code-generation/pom.xml                            |   2 +-
 .../spi/codegen/fields/FieldReaderFactory.java     |  13 +
 .../spi/codegen/fields/FieldReaderReserved.java    |   3 +-
 .../spi/codegen/fields/FieldReaderUnknown.java     |   5 +-
 .../java/spi/codegen/io/DataReaderFactory.java     |  54 +-
 .../java/spi/codegen/io/DataReaderSimple.java      |   8 -
 .../spi/codegen/io/DataReaderSimpleBigDecimal.java |   6 +-
 .../spi/codegen/io/DataReaderSimpleBoolean.java    |  10 +-
 .../java/spi/codegen/io/DataReaderSimpleByte.java  |   6 +-
 .../spi/codegen/io/DataReaderSimpleByteArray.java  |  14 +-
 .../spi/codegen/io/DataReaderSimpleDouble.java     |   6 +-
 .../java/spi/codegen/io/DataReaderSimpleFloat.java |   6 +-
 .../io/DataReaderSimpleSignedBigInteger.java       |   6 +-
 .../spi/codegen/io/DataReaderSimpleSignedByte.java |   6 +-
 .../spi/codegen/io/DataReaderSimpleSignedInt.java  |   6 +-
 .../spi/codegen/io/DataReaderSimpleSignedLong.java |   6 +-
 .../codegen/io/DataReaderSimpleSignedShort.java    |   6 +-
 .../spi/codegen/io/DataReaderSimpleString.java     |   6 +-
 .../io/DataReaderSimpleUnsignedBigInteger.java     |  11 +-
 .../codegen/io/DataReaderSimpleUnsignedByte.java   |   6 +-
 .../codegen/io/DataReaderSimpleUnsignedInt.java    |   6 +-
 .../codegen/io/DataReaderSimpleUnsignedLong.java   |   6 +-
 .../codegen/io/DataReaderSimpleUnsignedShort.java  |  11 +-
 44 files changed, 292 insertions(+), 2195 deletions(-)

diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java
index de98895..edb02e9 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java
@@ -28,12 +28,15 @@ public interface FreemarkerLanguageTemplateHelper {
 
     String getLanguageTypeNameForTypeReference(TypeReference typeReference);
 
+    @Deprecated
     default String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
         return getReadBufferReadMethodCall(simpleTypeReference, null, null);
     }
 
+    @Deprecated
     String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field);
 
+    @Deprecated
     String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName, TypedField field);
 
     String getNullValueForTypeReference(TypeReference typeReference);
diff --git a/code-generation/language-c/pom.xml b/code-generation/language-c/pom.xml
index 1bb5a10..2a8f589 100644
--- a/code-generation/language-c/pom.xml
+++ b/code-generation/language-c/pom.xml
@@ -55,6 +55,13 @@
               <projectsDirectory>src/test/resources</projectsDirectory>
               <cloneProjectsTo>${project.build.directory}/integration-tests</cloneProjectsTo>
               <settingsFile>src/test/resources/settings.xml</settingsFile>
+              <extraArtifacts>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-language-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-maven-plugin:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-protocol-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+              </extraArtifacts>
               <pomIncludes>
                 <pomInclude>*/pom.xml</pomInclude>
               </pomIncludes>
diff --git a/code-generation/language-go/pom.xml b/code-generation/language-go/pom.xml
index 191dfae..d73e417 100644
--- a/code-generation/language-go/pom.xml
+++ b/code-generation/language-go/pom.xml
@@ -34,7 +34,45 @@
 
   <build>
     <plugins>
-
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-invoker-plugin</artifactId>
+        <version>3.2.2</version>
+        <executions>
+          <execution>
+            <id>integration-test</id>
+            <goals>
+              <!-- Install the current project artifacts into the maven local repo, so they can be used in the test -->
+              <goal>install</goal>
+              <!-- Execute the maven builds defines in src/test/resources -->
+              <goal>integration-test</goal>
+              <!-- Checks the results of the maven builds -->
+              <goal>verify</goal>
+            </goals>
+            <configuration>
+              <debug>true</debug>
+              <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+              <projectsDirectory>src/test/resources</projectsDirectory>
+              <cloneProjectsTo>${project.build.directory}/integration-tests</cloneProjectsTo>
+              <settingsFile>src/test/resources/settings.xml</settingsFile>
+              <extraArtifacts>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-language-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-maven-plugin:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-protocol-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+              </extraArtifacts>
+              <pomIncludes>
+                <pomInclude>*/pom.xml</pomInclude>
+              </pomIncludes>
+              <!-- The goals we will be executing in the test-projects -->
+              <goals>
+                <goal>test</goal>
+              </goals>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java b/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
deleted file mode 100644
index f01fca1..0000000
--- a/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
+++ /dev/null
@@ -1,103 +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 com.google.googlejavaformat.java.Formatter;
-import com.google.googlejavaformat.java.FormatterException;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import org.apache.commons.io.FileUtils;
-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.TypeDefinition;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-
-public class JavaLanguageOutput extends FreemarkerLanguageOutput {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(JavaLanguageOutput.class);
-
-    private final Formatter formatter = new Formatter();
-
-    @Override
-    public String getName() {
-        return "Java";
-    }
-
-    @Override
-    public Set<String> supportedOptions() {
-        return Collections.singleton("package");
-    }
-
-    @Override
-    public List<String> supportedOutputFlavors() {
-        return Arrays.asList("read-write", "read-only", "passive");
-    }
-
-    @Override
-    protected List<Template> getSpecTemplates(Configuration freemarkerConfiguration) throws IOException {
-        return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/java/enum-package-info-template.java.ftlh"));
-    }
-
-    @Override
-    protected List<Template> getComplexTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
-        return Arrays.asList(
-            freemarkerConfiguration.getTemplate("templates/java/pojo-template.java.ftlh"),
-            freemarkerConfiguration.getTemplate("templates/java/io-template.java.ftlh"));
-    }
-
-    @Override
-    protected List<Template> getEnumTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
-        return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/java/enum-template.java.ftlh"));
-    }
-
-    @Override
-    protected List<Template> getDataIoTemplates(Configuration freemarkerConfiguration) throws IOException {
-        return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/java/data-io-template.java.ftlh"));
-    }
-
-    @Override
-    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
-                                                         Map<String, String> options) {
-        return new JavaLanguageTemplateHelper(thisType, protocolName, flavorName, types, options);
-    }
-
-    @Override
-    protected void postProcessTemplateOutput(File outputFile) {
-        try {
-            FileUtils.writeStringToFile(
-                outputFile,
-                formatter.formatSourceAndFixImports(
-                    FileUtils.readFileToString(outputFile, StandardCharsets.UTF_8)
-                ),
-                StandardCharsets.UTF_8
-            );
-        } catch (IOException | FormatterException e) {
-            LOGGER.error("Error formatting {}", outputFile, e);
-        }
-    }
-}
diff --git a/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
deleted file mode 100644
index 04337bf..0000000
--- a/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ /dev/null
@@ -1,984 +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 org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.commons.text.WordUtils;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer;
-import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
-import org.apache.plc4x.plugins.codegenerator.types.fields.*;
-import org.apache.plc4x.plugins.codegenerator.types.references.*;
-import org.apache.plc4x.plugins.codegenerator.types.terms.*;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-
-@SuppressWarnings({"unused", "WeakerAccess"})
-public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
-
-    private final Map<String, String> options;
-
-    public JavaLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
-                                      Map<String, String> options) {
-        super(thisType, protocolName, flavorName, types);
-        this.options = options;
-    }
-
-    public String packageName(String protocolName, String languageName, String languageFlavorName) {
-        return Optional.ofNullable(options.get("package")).orElseGet(() ->
-            "org.apache.plc4x." + String.join("", languageName.split("\\-")) + "." +
-                String.join("", protocolName.split("\\-")) + "." +
-                String.join("", languageFlavorName.split("\\-")));
-    }
-
-    @Override
-    public String getLanguageTypeNameForField(Field field) {
-        // If the referenced type is a DataIo type, the value is of type PlcValue.
-        if (field.isPropertyField()) {
-            PropertyField propertyField = field.asPropertyField().orElseThrow(IllegalStateException::new);
-            if (propertyField.getType().isComplexTypeReference()) {
-                ComplexTypeReference complexTypeReference = propertyField.getType().asComplexTypeReference().orElseThrow(IllegalStateException::new);
-                final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
-                if (typeDefinition instanceof DataIoTypeDefinition) {
-                    return "PlcValue";
-                }
-            }
-        }
-        return getLanguageTypeNameForTypeReference(((TypedField) field).getType(), !field.isOptionalField());
-    }
-
-    public String getNonPrimitiveLanguageTypeNameForField(TypedField field) {
-        return getLanguageTypeNameForTypeReference(field.getType(), false);
-    }
-
-    public String getLanguageTypeNameForSpecType(TypeReference typeReference) {
-        return getLanguageTypeNameForTypeReference(typeReference, true);
-    }
-
-    @Override
-    public String getLanguageTypeNameForTypeReference(TypeReference typeReference) {
-        return getLanguageTypeNameForTypeReference(typeReference, false);
-    }
-
-    public String adjustLiterals(String javaType, String value) {
-        switch (javaType) {
-            case "long":
-            case "Long":
-                return value + "L";
-            default:
-                return value;
-        }
-    }
-
-    public String getLanguageTypeNameForTypeReference(TypeReference typeReference, boolean allowPrimitive) {
-        if (typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case BIT:
-                    return allowPrimitive ? boolean.class.getSimpleName() : Boolean.class.getSimpleName();
-                case BYTE:
-                    return allowPrimitive ? byte.class.getSimpleName() : Byte.class.getSimpleName();
-                case UINT:
-                    IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
-                        return allowPrimitive ? byte.class.getSimpleName() : Byte.class.getSimpleName();
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
-                        return allowPrimitive ? short.class.getSimpleName() : Short.class.getSimpleName();
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
-                        return allowPrimitive ? int.class.getSimpleName() : Integer.class.getSimpleName();
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
-                        return allowPrimitive ? long.class.getSimpleName() : Long.class.getSimpleName();
-                    }
-                    return BigInteger.class.getSimpleName();
-                case INT:
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 8) {
-                        return allowPrimitive ? byte.class.getSimpleName() : Byte.class.getSimpleName();
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 16) {
-                        return allowPrimitive ? short.class.getSimpleName() : Short.class.getSimpleName();
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return allowPrimitive ? int.class.getSimpleName() : Integer.class.getSimpleName();
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return allowPrimitive ? long.class.getSimpleName() : Long.class.getSimpleName();
-                    }
-                    return BigInteger.class.getSimpleName();
-                case FLOAT:
-                case UFLOAT:
-                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                    int sizeInBits = floatTypeReference.getSizeInBits();
-                    if (sizeInBits <= 32) {
-                        return allowPrimitive ? float.class.getSimpleName() : Float.class.getSimpleName();
-                    }
-                    if (sizeInBits <= 64) {
-                        return allowPrimitive ? double.class.getSimpleName() : Double.class.getSimpleName();
-                    }
-                    return BigDecimal.class.getSimpleName();
-                case STRING:
-                case VSTRING:
-                    return String.class.getSimpleName();
-                case TIME:
-                    return LocalTime.class.getSimpleName();
-                case DATE:
-                    return LocalDate.class.getSimpleName();
-                case DATETIME:
-                    return LocalDateTime.class.getSimpleName();
-
-            }
-            throw new RuntimeException("Unsupported simple type");
-        } else {
-            return ((ComplexTypeReference) typeReference).getName();
-        }
-    }
-
-    public String getPlcValueTypeForTypeReference(TypeReference typeReference) {
-        if (typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case BIT:
-                    return "PlcBOOL";
-                case BYTE:
-                    return "PlcSINT";
-                case UINT:
-                    IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
-                        return "PlcUSINT";
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
-                        return "PlcUINT";
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
-                        return "PlcUDINT";
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
-                        return "PlcULINT";
-                    }
-                case INT:
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 8) {
-                        return "PlcSINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 16) {
-                        return "PlcINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return "PlcDINT";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return "PlcLINT";
-                    }
-
-                case FLOAT:
-                case UFLOAT:
-                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                    int sizeInBits = floatTypeReference.getSizeInBits();
-                    if (sizeInBits <= 32) {
-                        return "PlcREAL";
-                    }
-                    if (sizeInBits <= 64) {
-                        return "PlcLREAL";
-                    }
-                case STRING:
-                case VSTRING:
-                    return "PlcSTRING";
-                case TIME:
-                case DATE:
-                case DATETIME:
-                    return "PlcTIME";
-            }
-            throw new RuntimeException("Unsupported simple type");
-        } else {
-            return "PlcStruct";
-        }
-    }
-
-    @Override
-    public String getNullValueForTypeReference(TypeReference typeReference) {
-        if (typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case BIT:
-                    return "false";
-                case BYTE:
-                    return "0";
-                case UINT:
-                    IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
-                        return "0";
-                    }
-                    if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
-                        return "0l";
-                    }
-                    return "null";
-                case INT:
-                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                    if (integerTypeReference.getSizeInBits() <= 32) {
-                        return "0";
-                    }
-                    if (integerTypeReference.getSizeInBits() <= 64) {
-                        return "0l";
-                    }
-                    return "null";
-                case FLOAT:
-                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                    int sizeInBits = floatTypeReference.getSizeInBits();
-                    if (sizeInBits <= 32) {
-                        return "0.0f";
-                    }
-                    if (sizeInBits <= 64) {
-                        return "0.0";
-                    }
-                    return "null";
-                case STRING:
-                case VSTRING:
-                    return "null";
-            }
-            throw new FreemarkerException("Unmapped basetype" + simpleTypeReference.getBaseType());
-        } else {
-            return "null";
-        }
-    }
-
-    /*public String getArgumentType(TypeReference typeReference, int index) {
-        if(typeReference instanceof ComplexTypeReference) {
-            ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
-            if(!getTypeDefinitions().containsKey(complexTypeReference.getName())) {
-                throw new RuntimeException("Could not find definition of complex type " + complexTypeReference.getName());
-            }
-            TypeDefinition complexTypeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
-            if(complexTypeDefinition.getParserArguments().length <= index) {
-                throw new RuntimeException("Type " + complexTypeReference.getName() + " specifies too few parser arguments");
-            }
-            return getLanguageTypeNameForSpecType(complexTypeDefinition.getParserArguments()[index].getType());
-        }
-        return "Hurz";
-    }*/
-
-    public int getNumBits(SimpleTypeReference simpleTypeReference) {
-        switch (simpleTypeReference.getBaseType()) {
-            case BIT:
-                return 1;
-            case BYTE:
-                return 8;
-            case UINT:
-            case INT:
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                return integerTypeReference.getSizeInBits();
-            case FLOAT:
-                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                return floatTypeReference.getSizeInBits();
-            case STRING:
-            case VSTRING:
-                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return stringTypeReference.getSizeInBits();
-            default:
-                return 0;
-        }
-    }
-
-    @Override
-    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
-        return "/* Not used in this module */ (" + getLanguageTypeNameForTypeReference(simpleTypeReference) + ")" + getNullValueForTypeReference(simpleTypeReference);
-    }
-
-    @Override
-    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
-        return "/* Not used in this module */ (" + getLanguageTypeNameForTypeReference(simpleTypeReference) + ")" + getNullValueForTypeReference(simpleTypeReference);
-    }
-
-    public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
-        return "/* Not used in this module */ (" + getLanguageTypeNameForTypeReference(simpleTypeReference) + ")" + getNullValueForTypeReference(simpleTypeReference);
-    }
-
-    public String getDataReaderCall(TypeReference typeReference) {
-        if (isEnumTypeReference(typeReference)) {
-            final String languageTypeName = getLanguageTypeNameForTypeReference(typeReference);
-            final SimpleTypeReference enumBaseTypeReference = getEnumBaseTypeReference(typeReference);
-            return "new DataReaderEnumDefault(" + languageTypeName + "::enumForValue, " + getDataReaderCall(enumBaseTypeReference) + ")";
-        } else if (typeReference.isSimpleTypeReference()) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            return getDataReaderCall(simpleTypeReference);
-        } else if (typeReference.isComplexTypeReference()) {
-            return "new DataReaderComplex(readBuffer)";
-        } else {
-            throw new IllegalStateException("What is this type? " + typeReference);
-        }
-    }
-
-    public String getDataReaderCall(SimpleTypeReference simpleTypeReference) {
-        final int sizeInBits = simpleTypeReference.getSizeInBits();
-        switch (simpleTypeReference.getBaseType()) {
-            case BIT:
-                return "readBoolean(readBuffer)";
-            case BYTE:
-                return "readByte(readBuffer)";
-            case UINT:
-                if (sizeInBits <= 4) return "readUnsignedByte(readBuffer)";
-                if (sizeInBits <= 8) return "readUnsignedShort(readBuffer)";
-                if (sizeInBits <= 16) return "readUnsignedInt(readBuffer)";
-                if (sizeInBits <= 32) return "readUnsignedLong(readBuffer)";
-                return "readUnsignedBigInteger(readBuffer)";
-            case INT:
-                if (sizeInBits <= 8) return "readSignedByte(readBuffer)";
-                if (sizeInBits <= 16) return "readSignedShort(readBuffer)";
-                if (sizeInBits <= 32) return "readSignedInt(readBuffer)";
-                if (sizeInBits <= 64) return "readSignedLong(readBuffer)";
-                return "readSignedBigInteger(readBuffer)";
-            case FLOAT:
-                if (sizeInBits <= 32) return "readFloat(readBuffer)";
-                if (sizeInBits <= 64) return "readDouble(readBuffer)";
-                return "readBigDecimal(readBuffer)";
-            case STRING:
-            case VSTRING:
-                return "readString(readBuffer)";
-        }
-        return "";
-    }
-
-    @Override
-    public String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName, TypedField field) {
-        return getWriteBufferWriteMethodCall("", simpleTypeReference, fieldName, field);
-    }
-
-    public String getWriteBufferWriteMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String fieldName, TypedField field, String... writerArgs) {
-        String writerArgsString = "";
-        if (writerArgs.length > 0) {
-            writerArgsString += ", " + StringUtils.join(writerArgs, ", ");
-        }
-        switch (simpleTypeReference.getBaseType()) {
-            case BIT:
-                return "writeBuffer.writeBit(\"" + logicalName + "\", (boolean) " + fieldName + "" + writerArgsString + ")";
-            case BYTE:
-                ByteTypeReference byteTypeReference = (ByteTypeReference) simpleTypeReference;
-                return "writeBuffer.writeByte(\"" + logicalName + "\", ((Number) " + fieldName + ").byteValue()" + writerArgsString + ")";
-            case UINT:
-                IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
-                    return "writeBuffer.writeUnsignedByte(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").byteValue()" + writerArgsString + ")";
-                }
-                if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
-                    return "writeBuffer.writeUnsignedShort(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").shortValue()" + writerArgsString + ")";
-                }
-                if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
-                    return "writeBuffer.writeUnsignedInt(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").intValue()" + writerArgsString + ")";
-                }
-                if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
-                    return "writeBuffer.writeUnsignedLong(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").longValue()" + writerArgsString + ")";
-                }
-                return "writeBuffer.writeUnsignedBigInteger(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", (BigInteger) " + fieldName + "" + writerArgsString + ")";
-            case INT:
-                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
-                if (integerTypeReference.getSizeInBits() <= 8) {
-                    return "writeBuffer.writeSignedByte(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").byteValue()" + writerArgsString + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 16) {
-                    return "writeBuffer.writeShort(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").shortValue()" + writerArgsString + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 32) {
-                    return "writeBuffer.writeInt(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").intValue()" + writerArgsString + ")";
-                }
-                if (integerTypeReference.getSizeInBits() <= 64) {
-                    return "writeBuffer.writeLong(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").longValue()" + writerArgsString + ")";
-                }
-                return "writeBuffer.writeBigInteger(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", BigInteger.valueOf( " + fieldName + ")" + writerArgsString + ")";
-            case FLOAT:
-            case UFLOAT:
-                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
-                if (floatTypeReference.getSizeInBits() <= 32) {
-                    return "writeBuffer.writeFloat(\"" + logicalName + "\", " + floatTypeReference.getSizeInBits() + "," + fieldName + "" + writerArgsString + ")";
-                } else if (floatTypeReference.getSizeInBits() <= 64) {
-                    return "writeBuffer.writeDouble(\"" + logicalName + "\", " + floatTypeReference.getSizeInBits() + "," + fieldName + "" + writerArgsString + ")";
-                } else {
-                    throw new RuntimeException("Unsupported float type");
-                }
-            case STRING:
-            case VSTRING:
-                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return "writeBuffer.writeString(\"" + logicalName + "\", " + toSerializationExpression(field, stringTypeReference.getLengthExpression(), thisType.getParserArguments().orElse(Collections.emptyList())) + ", \"" +
-                    stringTypeReference.getEncoding() + "\", (String) " + fieldName + "" + writerArgsString + ")";
-        }
-        throw new FreemarkerException("Unmapped basetype" + simpleTypeReference.getBaseType());
-    }
-
-    /*public String getReadMethodName(SimpleTypeReference simpleTypeReference) {
-        String languageTypeName = getLanguageTypeNameForSpecType(simpleTypeReference);
-        languageTypeName = languageTypeName.substring(0, 1).toUpperCase() + languageTypeName.substring(1);
-        if(simpleTypeReference.getBaseType().equals(SimpleTypeReference.SimpleBaseType.UINT)) {
-            return "readUnsigned" + languageTypeName;
-        } else {
-            return "read" + languageTypeName;
-        }
-    }*/
-
-    public String getReservedValue(ReservedField reservedField) {
-        final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType(), true);
-        if ("BigInteger".equals(languageTypeName)) {
-            return "BigInteger.valueOf(" + reservedField.getReferenceValue() + ")";
-        } else {
-            return "(" + languageTypeName + ") " + reservedField.getReferenceValue();
-        }
-    }
-
-    /*public Collection<ComplexTypeReference> getComplexTypes(ComplexTypeDefinition complexTypeDefinition) {
-        Map<String, ComplexTypeReference> types = new HashMap<>();
-        for (Field field : complexTypeDefinition.getFields()) {
-            if(field instanceof TypedField) {
-                TypedField typedField = (TypedField) field;
-                if(typedField.getType() instanceof ComplexTypeReference) {
-                    ComplexTypeReference complexTypeReference = (ComplexTypeReference) typedField.getType();
-                    types.put(complexTypeReference.getName(),  complexTypeReference);
-                }
-            } else if(field instanceof SwitchField) {
-                SwitchField switchField = (SwitchField) field;
-                for (DiscriminatedComplexTypeDefinition cas : switchField.getCases()) {
-                    types.put(cas.getName(), new ComplexTypeReference() {
-                        @Override
-                        public String getName() {
-                            return cas.getName();
-                        }
-                    });
-                }
-            }
-        }
-        return types.values();
-    }*/
-
-    /*public Collection<ComplexTypeReference> getEnumTypes(ComplexTypeDefinition complexTypeDefinition) {
-        Map<String, ComplexTypeReference> types = new HashMap<>();
-        for (Field field : complexTypeDefinition.getFields()) {
-            if(field instanceof EnumField) {
-                EnumField enumField = (EnumField) field;
-                if(enumField.getType() instanceof ComplexTypeReference) {
-                    ComplexTypeReference complexTypeReference = (ComplexTypeReference) enumField.getType();
-                    types.put(complexTypeReference.getName(),  complexTypeReference);
-                }
-            }
-        }
-        for (Field field : complexTypeDefinition.getParentPropertyFields()) {
-            if(field instanceof EnumField) {
-                EnumField enumField = (EnumField) field;
-                if(enumField.getType() instanceof ComplexTypeReference) {
-                    ComplexTypeReference complexTypeReference = (ComplexTypeReference) enumField.getType();
-                    types.put(complexTypeReference.getName(),  complexTypeReference);
-                }
-            }
-        }
-        return types.values();
-    }*/
-
-    public String toAccessExpression(TypedField field, Term term, List<Argument> parserArguments) {
-        return toExpression(field, term, variableLiteral -> {
-            if (isVariableLiteralVirtualField(variableLiteral) || isVariableLiteralDiscriminatorField(variableLiteral)) { // If we are accessing virtual|discriminator fields, we need to call the getter.
-                return "get" + StringUtils.capitalize(variableLiteral.getName()) + "()";
-            }
-            return toVariableParseExpression(field, variableLiteral, parserArguments);
-        });
-    }
-
-    public String toParseExpression(TypedField field, Term term, List<Argument> parserArguments) {
-        Tracer tracer = Tracer.start("toParseExpression");
-        return tracer + toExpression(field, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableParseExpression(field, variableLiteral, parserArguments));
-    }
-
-    public String toSerializationExpression(TypedField field, Term term, List<Argument> serializerArguments) {
-        Tracer tracer = Tracer.start("toSerializationExpression");
-        return tracer + toExpression(field, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableSerializationExpression(field, variableLiteral, serializerArguments));
-    }
-
-    private String toExpression(TypedField field, Term term, Function<VariableLiteral, String> variableExpressionGenerator) {
-        Tracer tracer = Tracer.start("toExpression");
-        if (term == null) {
-            return tracer + "";
-        }
-        if (term instanceof Literal) {
-            return toLiteralTermExpression((Literal) term, variableExpressionGenerator, tracer);
-        } else if (term instanceof UnaryTerm) {
-            return toUnaryTermExpression(field, (UnaryTerm) term, variableExpressionGenerator, tracer);
-        } else if (term instanceof BinaryTerm) {
-            return toBinaryTermExpression(field, (BinaryTerm) term, variableExpressionGenerator, tracer);
-        } else if (term instanceof TernaryTerm) {
-            return toTernaryTermExpression(field, (TernaryTerm) term, variableExpressionGenerator, tracer);
-        } else {
-            throw new RuntimeException("Unsupported Term type " + term.getClass().getName());
-        }
-    }
-
-    private String toLiteralTermExpression(Literal literal, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
-        tracer = tracer.dive("literal term instanceOf");
-        if (literal instanceof NullLiteral) {
-            tracer = tracer.dive("null literal instanceOf");
-            return tracer + "null";
-        } else if (literal instanceof BooleanLiteral) {
-            tracer = tracer.dive("boolean literal instanceOf");
-            return tracer + Boolean.toString(((BooleanLiteral) literal).getValue());
-        } else if (literal instanceof NumericLiteral) {
-            tracer = tracer.dive("numeric literal instanceOf");
-            return tracer + ((NumericLiteral) literal).getNumber().toString();
-        } else if (literal instanceof StringLiteral) {
-            tracer = tracer.dive("string literal instanceOf");
-            return tracer + "\"" + ((StringLiteral) literal).getValue() + "\"";
-        } else if (literal instanceof VariableLiteral) {
-            tracer = tracer.dive("variable literal instanceOf");
-            VariableLiteral variableLiteral = (VariableLiteral) literal;
-            // If this literal references an Enum type, then we have to output it differently.
-            if (getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
-                tracer = tracer.dive("enum definition instanceOf");
-                VariableLiteral enumDefinitionChild = variableLiteral.getChild()
-                    .orElseThrow(() -> new RuntimeException("enum definitions should have childs"));
-                return tracer + variableLiteral.getName() + "." + enumDefinitionChild.getName() +
-                    enumDefinitionChild.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
-            } else {
-                return tracer + variableExpressionGenerator.apply(variableLiteral);
-            }
-        } else {
-            throw new RuntimeException("Unsupported Literal type " + literal.getClass().getName());
-        }
-    }
-
-    private String toUnaryTermExpression(TypedField field, UnaryTerm unaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
-        tracer = tracer.dive("unary term instanceOf");
-        Term a = unaryTerm.getA();
-        switch (unaryTerm.getOperation()) {
-            case "!":
-                tracer = tracer.dive("case !");
-                return tracer + "!(" + toExpression(field, a, variableExpressionGenerator) + ")";
-            case "-":
-                tracer = tracer.dive("case -");
-                return tracer + "-(" + toExpression(field, a, variableExpressionGenerator) + ")";
-            case "()":
-                tracer = tracer.dive("case ()");
-                return tracer + "(" + toExpression(field, a, variableExpressionGenerator) + ")";
-            default:
-                throw new RuntimeException("Unsupported unary operation type " + unaryTerm.getOperation());
-        }
-    }
-
-    private String toBinaryTermExpression(TypedField field, BinaryTerm binaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
-        tracer = tracer.dive("binary term instanceOf");
-        Term a = binaryTerm.getA();
-        Term b = binaryTerm.getB();
-        String operation = binaryTerm.getOperation();
-        switch (operation) {
-            case "^":
-                tracer = tracer.dive("^");
-                return tracer + "Math.pow((" + toExpression(field, a, variableExpressionGenerator) + "), (" + toExpression(field, b, variableExpressionGenerator) + "))";
-            default:
-                return tracer + "(" + toExpression(field, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, b, variableExpressionGenerator) + ")";
-        }
-    }
-
-    private String toTernaryTermExpression(TypedField field, TernaryTerm ternaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
-        tracer = tracer.dive("ternary term instanceOf");
-        if ("if".equals(ternaryTerm.getOperation())) {
-            Term a = ternaryTerm.getA();
-            Term b = ternaryTerm.getB();
-            Term c = ternaryTerm.getC();
-            return tracer + "((" + toExpression(field, a, variableExpressionGenerator) + ") ? " + toExpression(field, b, variableExpressionGenerator) + " : " + toExpression(field, c, variableExpressionGenerator) + ")";
-        } else {
-            throw new RuntimeException("Unsupported ternary operation type " + ternaryTerm.getOperation());
-        }
-    }
-
-    public String toVariableEnumAccessExpression(VariableLiteral variableLiteral) {
-        return variableLiteral.getName();
-    }
-
-    private String toVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments) {
-        Tracer tracer = Tracer.start("toVariableParseExpression");
-        // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
-        if ("CAST".equals(variableLiteral.getName())) {
-            return toCastVariableParseExpression(field, variableLiteral, parserArguments, tracer);
-        } else if ("STATIC_CALL".equals(variableLiteral.getName())) {
-            return toStaticCallVariableParseExpression(field, variableLiteral, parserArguments, tracer);
-        } else if (isVariableLiteralImplicitField(variableLiteral)) { // If we are accessing implicit fields, we need to rely on a local variable instead.
-            return toImplictVariableParseExpression(variableLiteral, tracer);
-        } else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) { // All uppercase names are not fields, but utility methods.
-            return toUpperCaseVariableParseExpression(field, variableLiteral, parserArguments, tracer);
-        }
-        return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
-    }
-
-    private String toUpperCaseVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
-        tracer = tracer.dive("UPPERCASE");
-        StringBuilder sb = new StringBuilder(variableLiteral.getName());
-        if (variableLiteral.getArgs().isPresent()) {
-            sb.append("(");
-            boolean firstArg = true;
-            for (Term arg : variableLiteral.getArgs().get()) {
-                if (!firstArg) {
-                    sb.append(", ");
-                }
-                sb.append(toParseExpression(field, arg, parserArguments));
-                firstArg = false;
-            }
-            sb.append(")");
-        }
-        if (variableLiteral.getIndex() != VariableLiteral.NO_INDEX) {
-            sb.append("[").append(variableLiteral.getIndex()).append("]");
-        }
-        return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
-    }
-
-    private String toImplictVariableParseExpression(VariableLiteral variableLiteral, Tracer tracer) {
-        tracer = tracer.dive("implicit");
-        return tracer + variableLiteral.getName();
-    }
-
-    private String toStaticCallVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
-        tracer = tracer.dive("STATIC_CALL");
-        StringBuilder sb = new StringBuilder();
-        List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
-        if (arguments.size() < 1) {
-            throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
-        }
-        // Get the class and method name
-        String methodName = arguments.get(0).asLiteral()
-            .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
-            .asStringLiteral()
-            .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
-            getValue();
-        // Cut off the double-quotes
-        methodName = methodName.substring(1, methodName.length() - 1);
-        sb.append(methodName).append("(");
-        for (int i = 1; i < arguments.size(); i++) {
-            Term arg = arguments.get(i);
-            if (i > 1) {
-                sb.append(", ");
-            }
-            if (arg instanceof VariableLiteral) {
-                VariableLiteral variableLiteralArg = (VariableLiteral) arg;
-                // "readBuffer" is the default name of the reader argument which is always available.
-                boolean isParserArg = "readBuffer".equals(variableLiteralArg.getName());
-                boolean isTypeArg = "_type".equals(variableLiteralArg.getName());
-                if (!isParserArg && !isTypeArg && parserArguments != null) {
-                    for (Argument parserArgument : parserArguments) {
-                        if (parserArgument.getName().equals(variableLiteralArg.getName())) {
-                            isParserArg = true;
-                            break;
-                        }
-                    }
-                }
-                if (isParserArg) {
-                    sb.append(variableLiteralArg.getName()).append(variableLiteralArg.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
-                } else if (isTypeArg) {// We have to manually evaluate the type information at code-generation time.
-                    String part = variableLiteralArg.getChild().map(VariableLiteral::getName).orElse("");
-                    switch (part) {
-                        case "name":
-                            sb.append("\"").append(field.getTypeName()).append("\"");
-                            break;
-                        case "length":
-                            sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
-                            break;
-                        case "encoding":
-                            String encoding = ((StringTypeReference) field.getType()).getEncoding();
-                            // Cut off the single quotes.
-                            encoding = encoding.substring(1, encoding.length() - 1);
-                            sb.append("\"").append(encoding).append("\"");
-                            break;
-                    }
-                } else {
-                    sb.append(toVariableParseExpression(field, variableLiteralArg, null));
-                }
-            } else if (arg instanceof StringLiteral) {
-                sb.append(((StringLiteral) arg).getValue());
-            }
-        }
-        sb.append(")");
-        return tracer + sb.toString();
-    }
-
-    private String toCastVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
-        tracer = tracer.dive("CAST");
-        StringBuilder sb = new StringBuilder(variableLiteral.getName());
-        List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A Cast expression needs arguments"));
-        if (arguments.size() != 2) {
-            throw new RuntimeException("A CAST expression expects exactly two arguments.");
-        }
-        VariableLiteral firstArgument = arguments.get(0).asLiteral()
-            .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
-            .asVariableLiteral()
-            .orElseThrow(() -> new RuntimeException("First argument should be a Variable literal"));
-        VariableLiteral secondArgument = arguments.get(1).asLiteral().orElseThrow(() -> new RuntimeException("Second argument should be a literal"))
-            .asVariableLiteral()
-            .orElseThrow(() -> new RuntimeException("Second argument should be a Variable literal"));
-        sb.append("(")
-            .append(toVariableParseExpression(field, firstArgument, parserArguments))
-            .append(", ")
-            .append(secondArgument.getName()).append(".class)");
-        return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
-    }
-
-    private String toVariableSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments) {
-        Tracer tracer = Tracer.start("variable serialization expression");
-        if ("STATIC_CALL".equals(variableLiteral.getName())) {
-            return toStaticCallSerializationExpression(field, variableLiteral, serialzerArguments, tracer);
-        }
-        // All uppercase names are not fields, but utility methods.
-        else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) {
-            return toUpperCaseSerializationExpression(field, variableLiteral, serialzerArguments, tracer);
-        } else if (isVariableLiteralImplicitField(variableLiteral)) { // If we are accessing implicit fields, we need to rely on a local variable instead.
-            tracer = tracer.dive("implicit field");
-            return tracer + toSerializationExpression(getReferencedImplicitField(variableLiteral), getReferencedImplicitField(variableLiteral).getSerializeExpression(), serialzerArguments);
-        } else if (isVariableLiteralVirtualField(variableLiteral)) {
-            tracer = tracer.dive("virtual field");
-            return tracer + "_value." + toVariableExpressionRest(variableLiteral);
-        }
-        // The synthetic checksumRawData is a local field and should not be accessed as bean property.
-        boolean isSerializerArg = "checksumRawData".equals(variableLiteral.getName()) || "_value".equals(variableLiteral.getName()) || "element".equals(variableLiteral.getName()) || "size".equals(variableLiteral.getName());
-        boolean isTypeArg = "_type".equals(variableLiteral.getName());
-        if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
-            for (Argument serializerArgument : serialzerArguments) {
-                if (serializerArgument.getName().equals(variableLiteral.getName())) {
-                    isSerializerArg = true;
-                    break;
-                }
-            }
-        }
-        if (isSerializerArg) {
-            tracer = tracer.dive("serializer arg");
-            return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
-        } else if (isTypeArg) {
-            tracer = tracer.dive("type arg");
-            String part = variableLiteral.getChild().map(VariableLiteral::getName).orElse("");
-            switch (part) {
-                case "name":
-                    return tracer + "\"" + field.getTypeName() + "\"";
-                case "length":
-                    return tracer + "\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
-                case "encoding":
-                    String encoding = ((StringTypeReference) field.getType()).getEncoding();
-                    // Cut off the single quotes.
-                    encoding = encoding.substring(1, encoding.length() - 1);
-                    return tracer + "\"" + encoding + "\"";
-                default:
-                    return tracer + "";
-            }
-        } else {
-            return tracer + "_value." + toVariableExpressionRest(variableLiteral);
-        }
-    }
-
-    private String toUpperCaseSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments, Tracer tracer) {
-        tracer = tracer.dive("UPPER_CASE");
-        StringBuilder sb = new StringBuilder(variableLiteral.getName());
-        if (variableLiteral.getArgs().isPresent()) {
-            sb.append("(");
-            boolean firstArg = true;
-            for (Term arg : variableLiteral.getArgs().get()) {
-                if (!firstArg) {
-                    sb.append(", ");
-                }
-
-                if (arg instanceof VariableLiteral) {
-                    VariableLiteral va = (VariableLiteral) arg;
-                    boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName());
-                    boolean isTypeArg = "_type".equals(va.getName());
-                    if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
-                        for (Argument serializerArgument : serialzerArguments) {
-                            if (serializerArgument.getName().equals(va.getName())) {
-                                isSerializerArg = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (isSerializerArg) {
-                        sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
-                    } else if (isTypeArg) {
-                        String part = va.getChild().map(VariableLiteral::getName).orElse("");
-                        switch (part) {
-                            case "name":
-                                sb.append("\"").append(field.getTypeName()).append("\"");
-                                break;
-                            case "length":
-                                sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
-                                break;
-                            case "encoding":
-                                String encoding = ((StringTypeReference) field.getType()).getEncoding();
-                                // Cut off the single quotes.
-                                encoding = encoding.substring(1, encoding.length() - 1);
-                                sb.append("\"").append(encoding).append("\"");
-                                break;
-                        }
-                    } else {
-                        sb.append(toVariableSerializationExpression(field, va, serialzerArguments));
-                    }
-                } else if (arg instanceof StringLiteral) {
-                    sb.append(((StringLiteral) arg).getValue());
-                }
-                firstArg = false;
-            }
-            sb.append(")");
-        }
-        return tracer + sb.toString();
-    }
-
-    private String toStaticCallSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments, Tracer tracer) {
-        tracer = tracer.dive("STATIC_CALL");
-        StringBuilder sb = new StringBuilder();
-        List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
-        if (arguments.size() < 1) {
-            throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
-        }
-        // Get the class and method name
-        String methodName = arguments.get(0).asLiteral()
-            .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
-            .asStringLiteral()
-            .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
-            getValue();
-        methodName = methodName.substring(1, methodName.length() - 1);
-        sb.append(methodName).append("(");
-        for (int i = 1; i < arguments.size(); i++) {
-            Term arg = arguments.get(i);
-            if (i > 1) {
-                sb.append(", ");
-            }
-            if (arg instanceof VariableLiteral) {
-                VariableLiteral va = (VariableLiteral) arg;
-                // "readBuffer" and "_value" are always available in every parser.
-                boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName()) || "_value".equals(va.getName()) || "element".equals(va.getName());
-                boolean isTypeArg = "_type".equals(va.getName());
-                if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
-                    for (Argument serializerArgument : serialzerArguments) {
-                        if (serializerArgument.getName().equals(va.getName())) {
-                            isSerializerArg = true;
-                            break;
-                        }
-                    }
-                }
-                if (isSerializerArg) {
-                    sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
-                } else if (isTypeArg) {
-                    String part = va.getChild().map(VariableLiteral::getName).orElse("");
-                    switch (part) {
-                        case "name":
-                            sb.append("\"").append(field.getTypeName()).append("\"");
-                            break;
-                        case "length":
-                            sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
-                            break;
-                        case "encoding":
-                            String encoding = ((StringTypeReference) field.getType()).getEncoding();
-                            // Cut off the single quotes.
-                            encoding = encoding.substring(1, encoding.length() - 1);
-                            sb.append("\"").append(encoding).append("\"");
-                            break;
-                    }
-                } else {
-                    sb.append(toVariableSerializationExpression(field, va, serialzerArguments));
-                }
-            } else if (arg instanceof StringLiteral) {
-                sb.append(((StringLiteral) arg).getValue());
-            }
-        }
-        sb.append(")");
-        return tracer + sb.toString();
-    }
-
-    private String toVariableExpressionRest(VariableLiteral variableLiteral) {
-        Tracer tracer = Tracer.start("variable expression rest");
-        // length is kind of a keyword in mspec, so we shouldn't be naming variables length. if we ask for the length of a object we can just return length().
-        // This way we can get the length of a string when serializing
-        String variableLiteralName = variableLiteral.getName();
-        if (variableLiteralName.equals("length")) {
-            tracer = tracer.dive("length");
-            return tracer + variableLiteralName + "()" + ((variableLiteral.isIndexed() ? "[" + variableLiteral.getIndex() + "]" : "") +
-                variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
-        }
-        return tracer + "get" + WordUtils.capitalize(variableLiteralName) + "()" + ((variableLiteral.isIndexed() ? "[" + variableLiteral.getIndex() + "]" : "") +
-            variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
-    }
-
-    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
-        int sizeInBits = 0;
-        StringBuilder sb = new StringBuilder();
-        for (Field field : complexTypeDefinition.getFields()) {
-            if (field instanceof ArrayField) {
-                ArrayField arrayField = (ArrayField) field;
-                final SimpleTypeReference type = (SimpleTypeReference) arrayField.getType();
-                switch (arrayField.getLoopType()) {
-                    case COUNT:
-                        sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), parserArguments)).append(" * ").append(type.getSizeInBits()).append(") + ");
-                        break;
-                    case LENGTH:
-                        sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), parserArguments)).append(" * 8) + ");
-                        break;
-                    case TERMINATED:
-                        // No terminated.
-                        break;
-                }
-            } else if (field instanceof TypedField) {
-                TypedField typedField = (TypedField) field;
-                final TypeReference type = typedField.getType();
-                if (field instanceof ManualField) {
-                    ManualField manualField = (ManualField) field;
-                    sb.append("(").append(toSerializationExpression(null, manualField.getLengthExpression(), parserArguments)).append(") + ");
-                } else if (type instanceof SimpleTypeReference) {
-                    SimpleTypeReference simpleTypeReference = (SimpleTypeReference) type;
-                    if (simpleTypeReference instanceof StringTypeReference) {
-                        sb.append(toSerializationExpression(null, ((StringTypeReference) simpleTypeReference).getLengthExpression(), parserArguments)).append(" + ");
-                    } else {
-                        sizeInBits += simpleTypeReference.getSizeInBits();
-                    }
-                } else {
-                    // No ComplexTypeReference supported.
-                }
-            }
-        }
-        return sb.toString() + sizeInBits;
-    }
-
-    public String escapeValue(TypeReference typeReference, String valueString) {
-        if (valueString == null) {
-            return null;
-        }
-        if (typeReference instanceof SimpleTypeReference) {
-            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
-            switch (simpleTypeReference.getBaseType()) {
-                case UINT:
-                case INT:
-                    // If it's a one character string and is numeric, output it as char.
-                    if (!NumberUtils.isParsable(valueString) && (valueString.length() == 1)) {
-                        return "'" + valueString + "'";
-                    }
-                    break;
-                case STRING:
-                case VSTRING:
-                    return "\"" + valueString + "\"";
-            }
-        }
-        return valueString;
-    }
-
-}
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java-ng/src/main/resources/templates/java/io-template.java.ftlh
deleted file mode 100644
index 00d4ec4..0000000
--- a/code-generation/language-java-ng/src/main/resources/templates/java/io-template.java.ftlh
+++ /dev/null
@@ -1,942 +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.
--->
-<#-- Prevent freemarker from escaping stuff -->
-<#outputformat "undefined">
-<#-- Declare the name and type of variables passed in to the template -->
-<#-- @ftlvariable name="languageName" type="java.lang.String" -->
-<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
-<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
-<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
-<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
-<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${type.name}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 ${helper.packageName(protocolName, languageName, outputFlavor)}.io;
-
-import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
-
-import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
-<#if helper.getComplexTypeReferences()?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if>
-import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
-
-import org.apache.plc4x.java.spi.codegen.fields.*;
-import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
-import org.apache.plc4x.java.spi.codegen.io.*;
-import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.spi.generation.*;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.math.BigInteger;
-import java.time.*;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.Supplier;
-
-// Code generated by code-generation. DO NOT EDIT.
-
-<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
-<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
-public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<${type.name}, ${type.name}><#else>MessageInput<${type.name}></#if> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
-
-<#-- The parse and serialize methods here are just proxies for forwardning the requests to static counterparts -->
-<#if !type.isDiscriminatedChildTypeDefinition()>
-    @Override
-    public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
-        <#if parserArguments?has_content>
-        if((args == null) || (args.length != ${parserArguments?size})) {
-            throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
-        }
-            <#list parserArguments as parserArgument>
-        ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name};
-        if(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) {
-            ${parserArgument.name} = (${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) args[${parserArgument?index}];
-            <#if helper.isSimpleTypeReference(parserArgument.type)>
-        } else if (args[${parserArgument?index}] instanceof String) {
-            ${parserArgument.name} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}.valueOf((String) args[${parserArgument?index}]);
-            </#if>
-        } else {
-            throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName());
-        }
-            </#list>
-        </#if>
-        return ${type.name}IO.staticParse(readBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
-    }
-
-    <#if outputFlavor != "passive">
-    @Override
-    public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException {
-        <#if helper.getSerializerArguments(parserArguments)?has_content>
-        if((args == null) || (args.length != ${parserArguments?size})) {
-            throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
-        }
-        <#list helper.getSerializerArguments(parserArguments) as serializerArgument>
-        if(!(args[${serializerArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)})) {
-            throw new PlcRuntimeException("Argument ${serializerArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} but was " + args[${serializerArgument?index}].getClass().getName());
-        }
-        ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)}) args[${serializerArgument?index}];
-        </#list>
-        </#if>
-        ${type.name}IO.staticSerialize(writeBuffer, value<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
-    }
-
-    </#if>
-<#else>
-    @Override
-    public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
-        return (${type.name}) new ${type.parentType.name}IO().parse(readBuffer, args);
-    }
-
-<#if outputFlavor != "passive">
-    @Override
-    public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException {
-        new ${type.parentType.name}IO().serialize(writeBuffer, value, args);
-    }
-
-</#if>
-</#if>
-<#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing -->
-    <#assign hasParserArguments=parserArguments?has_content/>
-    <#assign parserArgumentList><#if hasParserArguments><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-    <#assign hasParentParserArguments=(type.parentType?? && type.parentType.parserArguments.isPresent() && type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments)?has_content)>
-    <#assign parentParserArgumentList><#if hasParentParserArguments><#list type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-    public static ${type.name}<#if type.isDiscriminatedChildTypeDefinition()>Builder</#if> staticParse(ReadBuffer readBuffer<#if hasParserArguments>, ${parserArgumentList}</#if><#if hasParentParserArguments>, ${parentParserArgumentList}</#if>) throws ParseException {
-        readBuffer.pullContext("${type.name}");
-        int startPos = readBuffer.getPos();
-        int curPos;
-<#list type.fields as field>
-<#switch field.typeName>
-    <#case "array">
-        <#assign arrayField = field.asArrayField().orElseThrow()>
-        <#if arrayField.type.isByteBased()>
-        // Byte Array field (${arrayField.name})
-            <#assign numberOfBytesExpression>
-                <#compress>
-                    <#if field.isCountArrayField()>
-                        int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
-                    <#elseif field.isLengthArrayField()>
-                        int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
-                    <#elseif field.isTerminatedArrayField()>
-                    <#-- TODO: we need to find out to implement this-->
-                        int numberOfBytes := ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
-                    <#else>
-                    <#-- TODO: we should throw a exception here-->
-                        int numberOfBytes := -1
-                    </#if>
-                </#compress>
-            </#assign>
-        ${numberOfBytesExpression}
-        byte[] ${arrayField.name} = readBuffer.readByteArray("${arrayField.name}", numberOfBytes);
-        <#else>
-        // Array field (${arrayField.name})
-        readBuffer.pullContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-            <#-- Only update curPos if the length expression uses it -->
-            <#if arrayField.loopExpression.contains("curPos")>
-        curPos = readBuffer.getPos() - startPos;
-            </#if>
-        <#-- If this is a count array, we can directly initialize an array with the given size -->
-            <#if field.isCountArrayField()>
-        // Count array
-        if(${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)} > Integer.MAX_VALUE) {
-            throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
-        }
-        ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name};
-        {
-            int itemCount = Math.max(0, (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
-            ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
-            for(int curItem = 0; curItem < itemCount; curItem++) {
-                <#-- When parsing simple types, there is nothing that could require the "lastItem" -->
-                <#if !helper.isSimpleTypeReference(arrayField.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
-            <@compress single_line=true>
-                ${arrayField.name}[curItem] =
-                <#if helper.isSimpleTypeReference(arrayField.type)>
-                    ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
-                <#else>
-                    ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
-                    <#if field.params.isPresent()>
-                        ,
-                        <#list field.params.orElseThrow() as parserArgument>
-                            <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true) = 'String'>
-                                ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
-                            <#else>
-                                (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
-                            </#if>
-                        </#list>
-                    </#if>
-                    <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
-                    <#-- We expose the parentParserArguments to the child here too-->
-                    <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
-                    <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-                    <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
-                    )
-                    <#if helper.getTypeDefinitionForTypeReference(arrayField.type).isDiscriminatedChildTypeDefinition()>
-                        .build()
-                    </#if>
-                </#if>;
-            </...@compress>
-            }
-        }
-        <#-- 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 field.isLengthArrayField()>
-        // Length array
-        long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
-        long ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
-        while(readBuffer.getPos() < ${arrayField.name}EndPos) {
-                    <@compress single_line=true>
-            _${arrayField.name}List.add(
-                        <#if helper.isSimpleTypeReference(arrayField.type)>
-                            ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
-                        <#else>
-                            ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
-                            <#if field.params.isPresent()>
-                                ,
-                                <#list field.params.orElseThrow() as parserArgument>
-                                    (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
-                                    (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
-                                </#list>
-                            </#if>
-                            <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
-                        <#-- We expose the parentParserArguments to the child here too-->
-                            <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
-                            <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-                            <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
-                            )
-                        </#if>
-                        );
-                    </...@compress>
-            <#-- After parsing, update the current position, but only if it's needed -->
-                <#if arrayField.loopExpression.contains("curPos")>
-            curPos = readBuffer.getPos() - startPos;
-                </#if>
-        }
-            <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-                <#elseif field.isTerminatedArrayField()>
-        // Terminated array
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}))) {
-                    <@compress single_line=true>
-            _${arrayField.name}List.add(
-                        <#if helper.isSimpleTypeReference(arrayField.type)>
-                            ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
-                        <#else>
-                            ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
-                            <#if field.params.isPresent()>
-                                ,
-                                <#list field.params.orElseThrow() as parserArgument>
-                                    (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
-                                    (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
-                                </#list>
-                            </#if>
-                            <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
-                        <#-- We expose the parentParserArguments to the child here too-->
-                            <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
-                            <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-                            <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
-                            )
-                        </#if>
-                        );
-                    </...@compress>
-
-            <#-- After parsing, update the current position, but only if it's needed -->
-                <#if arrayField.loopExpression.contains("curPos")>
-            curPos = readBuffer.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.isSimpleTypeReference(arrayField.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${arrayField.name}List.size()];
-        for(int i = 0; i < _${arrayField.name}List.size(); i++) {
-            ${arrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${arrayField.name}List.get(i);
-        }
-                <#else>
-        ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]);
-                </#if>
-            </#if>
-            readBuffer.closeContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-        </#if>
-        <#break>
-    <#case "checksum">
-        <#assign checksumField = field.asChecksumField().orElseThrow()>
-        <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Checksum Field (checksum)
-        {
-            ${helper.getLanguageTypeNameForField(field)} checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
-            ${helper.getLanguageTypeNameForField(field)} checksumRef = ${helper.getReadBufferReadMethodCall("checksum", simpleTypeReference, "", checksumField)};
-            checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, parserArguments)});
-            if(checksum != checksumRef) {
-                throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X", checksumRef & 0xFFFF, checksum & 0xFFFF));
-            }
-        }
-        <#break>
-    <#case "const">
-        <#assign constField = field.asConstField().orElseThrow()>
-
-        // Const Field (${constField.name})
-        <#if helper.isSimpleTypeReference(constField.type)>
-            <#assign dataReaderCall>${helper.getDataReaderCall(constField.type)}</#assign>
-        <#else>
-            <#assign typeRefForDataCall = helper.getEnumBaseTypeReference(constField.type)>
-            <#assign dataReaderCall>new DataReaderEnumDefault(${helper.getLanguageTypeNameForField(field)}::enumForValue, ${helper.getDataReaderCall(typeRefForDataCall)})</#assign>
-        </#if>
-        ${helper.getLanguageTypeNameForField(field)} ${constField.name} = read${field.typeName?cap_first}Field("${constField.name}", ${dataReaderCall}, ${type.name}.${constField.name?upper_case});
-        <#break>
-    <#case "discriminator">
-        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
-
-        // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
-        <#if helper.isEnumField(field)>
-        ${helper.getLanguageTypeNameForField(discriminatorField)} ${discriminatorField.name} = ${helper.getLanguageTypeNameForField(discriminatorField)}.enumForValue(${helper.getReadBufferReadMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "", discriminatorField)});
-        <#else>
-            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
-            <@compress single_line=true>
-        ${helper.getLanguageTypeNameForField(discriminatorField)} ${discriminatorField.name} =
-                <#if helper.isSimpleTypeReference(discriminatorField.type)>
-                    ${helper.getReadBufferReadMethodCall(discriminatorField.name, simpleTypeReference, "", discriminatorField)}
-                <#else>
-                    ${discriminatorField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
-                    <#if discriminatorField.params.isPresent()>
-                        ,
-                        <#list discriminatorField.params.orElseThrow() as parserArgument>
-                            (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
-                            (${helper.toParseExpression(discriminatorField, parserArgument, null)})<#sep>, </#sep>
-                        </#list>
-                    </#if>
-                    )
-                </#if>;
-            </...@compress>
-        </#if>
-
-        <#break>
-    <#case "enum">
-        <#assign enumField = field.asEnumField().orElseThrow()>
-
-        readBuffer.pullContext("${enumField.name}");
-        // Enum field (${enumField.name})
-        <#if enumField.fieldName.isPresent()>
-        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.firstEnumForField${enumField.fieldName.orElseThrow()?cap_first}(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
-        <#else>
-        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
-        </#if>
-        readBuffer.closeContext("${enumField.name}");
-        <#break>
-    <#case "implicit">
-        <#assign implicitField = field.asImplicitField().orElseThrow()>
-        <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = ${helper.getReadBufferReadMethodCall(implicitField.name, simpleTypeReference, "", implicitField)};
-        <#break>
-    <#case "manualArray">
-        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
-
-        readBuffer.pullContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-        // Manual Array Field (${manualArrayField.name})
-        <#-- Only update curPos if the length expression uses it -->
-        <#if manualArrayField.loopExpression.contains("curPos")>
-        curPos = readBuffer.getPos() - startPos;
-        </#if>
-        <#-- If this is a count array, we can directly initialize an array with the given size -->
-        <#if field.isCountArrayField()>
-        // Count array
-        int _${manualArrayField.name}Count = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)};
-        ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}Count];
-        for(int i = 0; i < _${manualArrayField.name}Count; i++) {
-            ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, 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 field.isLengthArrayField()>
-        // Length array
-        long _${manualArrayField.name}Length = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)};
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
-        long ${manualArrayField.name}EndPos = readBuffer.getPos() + _${manualArrayField.name}Length;
-        while(readBuffer.getPos() < ${manualArrayField.name}EndPos) {
-            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)}));
-            <#-- After parsing, update the current position, but only if it's needed -->
-            <#if manualArrayField.loopExpression.contains("curPos")>
-            curPos = readBuffer.getPos() - startPos;
-            </#if>
-        }
-            <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-            <#elseif field.isTerminatedArrayField()>
-        // Terminated array
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)}))) {
-            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)}));
-
-            <#-- After parsing, update the current position, but only if it's needed -->
-            <#if manualArrayField.loopExpression.contains("curPos")>
-            curPos = readBuffer.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.isSimpleTypeReference(field.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}List.size()];
-        for(int i = 0; i < _${manualArrayField.name}List.size(); i++) {
-            ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${manualArrayField.name}List.get(i);
-        }
-            <#else>
-        ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = _${manualArrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}[0]);
-            </#if>
-        </#if>
-        readBuffer.closeContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-        <#break>
-    <#case "manual">
-        <#assign manualField = field.asManualField().orElseThrow()>
-
-        // Manual Field (${manualField.name})
-        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, parserArguments)});
-        <#break>
-    <#case "optional">
-        <#assign optionalField = field.asOptionalField().orElseThrow()>
-
-        // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
-        ${helper.getLanguageTypeNameForField(optionalField)} ${optionalField.name} = null;
-        <#-- TODO: we need to initalize base types-->
-        curPos = readBuffer.getPos();
-        try {
-        <#if optionalField.conditionExpression.present && optionalField.conditionExpression.orElseThrow().contains("curPos")>
-        curPos = readBuffer.getPos();
-        </#if>
-        <#if optionalField.conditionExpression.present>
-        if(${helper.toParseExpression(optionalField, optionalField.conditionExpression.get(), parserArguments)}) {
-        </#if>
-        <@compress single_line=true>
-            ${optionalField.name} =
-            <#if helper.isEnumField(optionalField)>
-             ${helper.getLanguageTypeNameForField(optionalField)}.enumForValue(
-                ${helper.getReadBufferReadMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "", optionalField)}
-            )
-            <#elseif helper.isComplexTypeReference(optionalField.type)>
-                <#assign complexTypeReference=optionalField.type.asComplexTypeReference().orElseThrow()>
-                <#assign typeName=complexTypeReference.name>
-                <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
-                <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
-                    <#-- Usually you don't use child directly unless they are parameterized #-->
-                    <#assign typeName=typeDefinition.parentType.name>
-                    <#assign typeDefinition=typeDefinition.parentType>
-                </#if>
-                <#-- We downcast to the referenced type-->
-            (${complexTypeReference.name}) ${typeName}IO.staticParse(
-                readBuffer
-                <#if field.params.isPresent()>,
-                    <#list field.params.orElseThrow() as parserArgument>
-                        (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(optionalField.type, parserArgument?index), true)})
-                        (${helper.toParseExpression(optionalField, parserArgument, parserArguments)})<#sep>, </#sep>
-                    </#list>
-                </#if>
-                <#if complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
-                    <#assign argumentOffset=0>
-                    <#if field.params.isPresent()><#assign argumentOffset=field.params.orElseThrow()?size></#if>
-                    ,
-                    <#list complexTypeReference.params.orElseThrow() as typeParam>
-                    <#-- We cast here explicitly as java sometimes can't infer the type. e.g. 0 is a int and not a byte#-->
-                        (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments.orElseThrow()[typeParam?index + argumentOffset].type, true)})
-                        ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
-                    </#list>
-                </#if>
-                )
-            <#else>
-             ${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type.asSimpleTypeReference().orElseThrow(), "", optionalField)}
-            </#if>
-            ;
-        </...@compress>
-
-        <#if optionalField.conditionExpression.present>
-        }
-        </#if>
-            if (1 == 2) {
-                throw new ParseAssertException("oh no java");
-            }
-        } catch(ParseAssertException ignore){
-            readBuffer.reset(curPos);
-        }
-        <#break>
-    <#case "assert">
-        <#assign assertField = field.asAssertField().orElseThrow()>
-
-        // Assert Field
-        <#if helper.isEnumField(assertField)>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getLanguageTypeNameForField(assertField)}.enumForValue(${helper.getReadBufferReadMethodCall(assertField.name, helper.getEnumBaseTypeReference(simpleTypeReference), "", assertField)});
-        <#elseif helper.isComplexTypeReference(assertField.type)>
-            <#assign complexTypeReference=assertField.type.asComplexTypeReference().orElseThrow()>
-            <#assign typeName=complexTypeReference.name>
-            <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
-            <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
-                <#assign typeName=typeDefinition.getParentType().name>
-            </#if>
-            <@compress single_line=true>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = (${complexTypeReference.name}) ${typeName}IO.staticParse(readBuffer
-                <#if field.params.isPresent()>
-                    ,
-                    <#list field.params.orElseThrow() as parserArgument>
-                        (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
-                        (${helper.toParseExpression(assertField, parserArgument, parserArguments)})<#sep>, </#sep>
-                    </#list>
-                </#if>
-                <#if complexTypeReference.params.isPresent()>
-                    ,
-                    <#list complexTypeReference.params.orElseThrow() as typeParam>
-                        ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
-                    </#list>
-                </#if>);
-            </...@compress>
-        <#else>
-            <#assign simpleTypeReference = assertField.type.asSimpleTypeReference().orElseThrow()>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getReadBufferReadMethodCall(assertField.name, simpleTypeReference.asSimpleTypeReference().orElseThrow(), "", assertField)};
-        </#if>
-        if(${assertField.name} != ${helper.toParseExpression(assertField.asTypedField().orElseThrow(), assertField.conditionExpression, parserArguments)}) {
-            throw new ParseAssertException("assertField ${assertField.name} with value " + ${assertField.name} + " didn't match the expected value " + ${helper.toParseExpression(assertField, assertField.conditionExpression, parserArguments)});
-        }
-        <#break>
-    <#case "padding">
-        <#assign paddingField = field.asPaddingField().orElseThrow()>
-        <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Padding Field (padding)
-        {
-            readBuffer.pullContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
-            int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)});
-            while ((readBuffer.hasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding-- > 0)) {
-                // Just read the padding data and ignore it
-                Object ignore = ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)};
-            }
-            readBuffer.closeContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
-        }
-        <#break>
-    <#case "reserved">
-        <#assign reservedField = field.asReservedField().orElseThrow()>
-        <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
-        {
-            ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall("reserved", simpleTypeReference, "", reservedField)};
-            if(reserved != ${helper.getReservedValue(reservedField)}) {
-                LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field.");
-            }
-        }
-        <#break>
-    <#case "simple">
-        <#assign simpleField = field.asSimpleField().orElseThrow()>
-
-        <#if !helper.isSimpleTypeReference(simpleField.type)>
-        readBuffer.pullContext("${simpleField.name}");
-        </#if>
-
-        // Simple Field (${simpleField.name})
-        <@compress single_line=true>
-        ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} =
-        <#assign simpleFieldLogicalName><#if helper.isSimpleTypeReference(simpleField.type)>${simpleField.name}<#else>${simpleField.typeName}</#if></#assign>
-        <#if helper.isEnumField(simpleField)>
-        /* enum based simple field with type ${simpleField.type.name} */
-        ${helper.getLanguageTypeNameForField(simpleField)}.enumForValue(
-            ${helper.getReadBufferReadMethodCall(simpleField.type.name, helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)}
-        );
-        <#elseif helper.isComplexTypeReference(simpleField.type)>
-            <#assign complexTypeReference = simpleField.type.asComplexTypeReference().orElseThrow()>
-            <#assign typeName=complexTypeReference.name>
-            <#assign typeDefinition = helper.getTypeDefinitionForTypeReference(complexTypeReference)>
-            <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
-                <#-- Usually you don't use child directly unless they are parameterized #-->
-                <#assign typeName=typeDefinition.parentType.name>
-                <#assign typeDefinition=typeDefinition.parentType>
-            </#if>
-                <#-- We downcast to the referenced type -->
-        (${simpleField.type.name}) ${typeName}IO.staticParse(readBuffer
-            <#if field.params.isPresent()>,
-                <#list field.params.orElseThrow() as parserArgument>
-                    <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true) = 'String'>
-            ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true)}
-                .valueOf(${helper.toParseExpression(simpleField, parserArgument, parserArguments)})<#sep>, </#sep>
-                    <#else>
-                (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true)})
-                (${helper.toParseExpression(simpleField, parserArgument, parserArguments)})<#sep>, </#sep>
-                    </#if>
-                </#list>
-            </#if>
-            <#if complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
-                <#assign argumentOffset=0>
-                <#if field.params.isPresent()><#assign argumentOffset=field.params.orElseThrow()?size></#if>
-            ,
-                    <#list complexTypeReference.params.orElseThrow() as typeParam>
-                            <#-- We cast here explicitly as java sometimes can't infer the type. e.g. 0 is a int and not a byte#-->
-            (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments.orElseThrow()[typeParam?index + argumentOffset].type, true)})
-            ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
-                    </#list>
-            </#if>
-                )
-        <#else>
-        ${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}
-        </#if>
-            ;
-        </...@compress>
-
-        <#if !helper.isSimpleTypeReference(simpleField.type)>
-        readBuffer.closeContext("${simpleField.name}");
-        </#if>
-
-        <#break>
-    <#case "switch">
-        <#assign switchField = field.asSwitchField().orElseThrow()>
-
-        // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
-        ${type.name}Builder builder = null;
-        <#list switchField.cases as case>
-            <@compress single_line=true>
-            <#if case.discriminatorValues?has_content>
-                if(
-                <#list case.discriminatorValues as discriminatorValue>
-                    <#assign discriminatorExpression=switchField.discriminatorExpressions[discriminatorValue?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
-                    EvaluationHelper.equals(
-                    ${helper.toParseExpression(null, discriminatorExpression, parserArguments)},
-                    <#if helper.discriminatorValueNeedsStringEqualityCheck(discriminatorExpression)>
-                        ${tracer.dive("discriminatorValueNeedsStringEqualityCheck")}"${discriminatorValue}"
-                    <#elseif helper.isComplexTypeReference(helper.getDiscriminatorTypes()[discriminatorExpression.name])>
-                        <#if helper.isEnumTypeReference(helper.getDiscriminatorTypes()[discriminatorExpression.name])>
-                            ${tracer.dive("isEnumTypeReference")}${helper.getDiscriminatorTypes()[discriminatorExpression.name].asComplexTypeReference().orElseThrow().name}.${discriminatorValue}
-                        <#else>
-                            ${tracer.dive("!isEnumTypeReference")}${discriminatorValue}
-                        </#if>
-                    <#else>
-                        ${tracer.dive("else")}${discriminatorValue}
-                    </#if>
-                    )
-                    <#sep> && </#sep>
-                    </#list>
-                )
-            </#if>{
-            </...@compress>
-            <@compress single_line=true>
-            <#assign hasCaseParseArguments=case.parserArguments.isPresent() && case.parserArguments.orElseThrow()?has_content>
-            <#assign caseParseArguments><#if hasCaseParseArguments><#list case.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-            <#-- We expose the parentParserArguments to the child here too-->
-            <#assign hasParentCaseParseArguments=case.parentType?? && case.parentType.parserArguments.isPresent() && case.parentType.parserArguments.orElseThrow()?filter(arg -> hasCaseParseArguments && !case.parserArguments.orElseThrow()?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments)?has_content>
-            <#assign parentCaseParseArguments><#if hasParentCaseParseArguments><#list case.parentType.parserArguments.orElseThrow()?filter(arg -> hasCaseParseArguments && !case.parserArguments.orElseThrow()?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-            builder = ${case.name}IO.staticParse(readBuffer<#if hasCaseParseArguments>, ${tracer.dive("case parse arguments")} ${caseParseArguments}</#if><#if hasParentCaseParseArguments>, ${tracer.dive("case parent parse arguments")} ${parentCaseParseArguments}</#if>);
-            </...@compress>
-        }<#sep> else </#sep>
-        </#list>
-        if (builder == null) {
-            throw new ParseException("Unsupported case for discriminated type");
-        }
-        <#break>
-
-    <#case "unknown">
-        <#assign unknownField = field.asUnknownField().orElseThrow()>
-        <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Unknown Field
-        ${helper.getReadBufferReadMethodCall("unknown" , simpleTypeReference, "", unknownField)};
-        <#break>
-
-    <#case "virtual">
-        <#assign virtualField = field.asVirtualField().orElseThrow()>
-
-        // Virtual field (Just declare a local variable so we can access it in the parser)
-        <#if helper.getLanguageTypeNameForField(field) = 'String'>
-        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)});
-        <#else>
-        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)});
-        </#if>
-        <#break>
-</#switch>
-</#list>
-
-        readBuffer.closeContext("${type.name}");
-        // Create the instance
-        <#if type.isDiscriminatedChildTypeDefinition()>
-        return new ${type.name}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        <#elseif type.isDiscriminatedParentTypeDefinition()>
-        return builder.build(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        <#else>
-        return new ${type.name}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        </#if>
-    }
-
-<#if outputFlavor != "passive">
-    public static void staticSerialize(WriteBuffer writeBuffer, ${type.name} _value<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
-    <#if helper.hasFieldOfType("unknown")>
-        throw new ParseException("Unknown field not serializable");
-    <#else>
-        int startPos = writeBuffer.getPos();
-        writeBuffer.pushContext("${type.name}");
-<#list type.fields as field>
-<#switch field.typeName>
-    <#case "array">
-        <#assign arrayField = field.asArrayField().orElseThrow()>
-
-        // Array Field (${arrayField.name})
-        if(_value.get${arrayField.name?cap_first}() != null) {
-            <#if arrayField.type.isByteBased()>
-            // Byte Array field (${arrayField.name})
-            writeBuffer.writeByteArray("${arrayField.name}", _value.get${arrayField.name?cap_first}());
-            <#else>
-            writeBuffer.pushContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-            int itemCount = (int) _value.get${arrayField.name?cap_first}().length;
-            int curItem = 0;
-            for(${helper.getLanguageTypeNameForField(arrayField)} element : _value.get${arrayField.name?cap_first}()) {
-                    <#if helper.isSimpleTypeReference(arrayField.type)>
-                        <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
-                ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "element", arrayField)};
-                    <#else>
-                        <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
-                boolean lastItem = curItem == (itemCount - 1);
-                ${complexTypeReference.name}IO.staticSerialize(writeBuffer, element<#if helper.getSerializerTerms(field.params.orElse(null))?has_content>, <#list helper.getSerializerTerms(field.params.orElseThrow()) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
-                    </#if>
-                curItem++;
-            }
-            writeBuffer.popContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-            </#if>
-        }
-        <#break>
-    <#case "checksum">
-        <#assign checksumField = field.asChecksumField().orElseThrow()>
-        <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Checksum Field (checksum) (Calculated)
-        {
-            ${helper.getLanguageTypeNameForField(field)} _checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
-            _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, parserArguments)});
-            ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", checksumField)};
-        }
-        <#break>
-    <#case "const">
-        <#assign constField = field.asConstField().orElseThrow()>
-
-        // Const Field (${constField.name})
-        <#if helper.isSimpleTypeReference(constField.type)>
-            <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
-            <#if helper.getLanguageTypeNameForField(field) = 'float'>
-        ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, constField.referenceValue + "f", constField)};
-            <#else>
-        ${helper.getWriteBufferWriteMethodCall(constField.name, simpleTypeReference, constField.referenceValue, constField)};
-            </#if>
-        <#else>
-            <#assign enumTypeReference = constField.type>
-            ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumTypeReference).name, helper.getEnumBaseTypeReference(enumTypeReference), "(" + type.name + "." + constField.name?upper_case + ".getValue())", constField, "WithReaderWriterArgs.WithAdditionalStringRepresentation("+ type.name + "." + constField.name?upper_case + ".name())")};
-        </#if>
-        <#break>
-    <#case "discriminator">
-        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
-
-        // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
-        ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${discriminatorField.name?cap_first}();
-        <#if helper.isSimpleTypeReference(discriminatorField.type)>
-            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
-            ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", discriminatorField)};
-        <#else>
-            <#assign complexTypeReference = discriminatorField.type>
-            <#if helper.isEnumField(field)>
-                ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "(" + discriminatorField.name + ".getValue())", discriminatorField)};
-            <#else>
-                ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${discriminatorField.name});
-            </#if>
-        </#if>
-        <#break>
-    <#case "enum">
-        <#assign enumField = field.asEnumField().orElseThrow()>
-
-        writeBuffer.pushContext("${enumField.name}");
-        // Enum field (${enumField.name})
-        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(enumField)}) _value.get${enumField.name?cap_first}();
-        <#if enumField.fieldName.isPresent()>
-        ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()), "(" + enumField.name + ".get" + enumField.fieldName.orElseThrow()?cap_first + "())", enumField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
-        <#else>
-        ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "(" + enumField.name + ".getValue())", enumField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
-        </#if>
-        writeBuffer.popContext("${enumField.name}");
-        <#break>
-    <#case "implicit">
-        <#assign implicitField = field.asImplicitField().orElseThrow()>
-        <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, parserArguments)});
-        ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", implicitField)};
-        <#break>
-    <#case "manualArray">
-        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
-
-        // Manual Array Field (${manualArrayField.name})
-        if(_value.get${manualArrayField.name?cap_first}() != null) {
-            writeBuffer.pushContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-            for(${helper.getLanguageTypeNameForField(field)} element : _value.get${manualArrayField.name?cap_first}()) {
-                ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, parserArguments)};
-            }
-            writeBuffer.popContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
-        }
-        <#break>
-    <#case "manual">
-        <#assign manualField = field.asTypedField().orElseThrow()>
-
-        // Manual Field (${manualField.name})
-        ${helper.toSerializationExpression(manualField, manualField.serializeExpression, parserArguments)};
-       <#break>
-    <#case "optional">
-        <#assign optionalField = field.asOptionalField().orElseThrow()>
-
-        // Optional Field (${optionalField.name}) (Can be skipped, if the value is null)
-        ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null;
-        if(_value.get${optionalField.name?cap_first}() != null) {
-            ${optionalField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${optionalField.name?cap_first}();
-            <#if helper.isSimpleTypeReference(optionalField.type)>
-                <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
-            ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "(" + optionalField.name + ")", optionalField)};
-            <#else>
-                <#assign complexTypeReference = optionalField.type>
-                <#if helper.isEnumField(field)>
-            ${helper.getWriteBufferWriteMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "(" + optionalField.name + ".getValue())", optionalField)};
-                <#else>
-            ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${optionalField.name});
-                </#if>
-            </#if>
-        }
-        <#break>
-    <#case "padding">
-        <#assign paddingField = field.asPaddingField().orElseThrow()>
-        <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Padding Field (padding)
-        {
-            writeBuffer.pushContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
-            int _timesPadding = (int) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, parserArguments)});
-            while (_timesPadding-- > 0) {
-                ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, parserArguments)});
-                ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", paddingField)};
-            }
-            writeBuffer.popContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
-        }
-        <#break>
-    <#case "reserved">
-        <#assign reservedField = field.asReservedField().orElseThrow()>
-        <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Reserved Field (reserved)
-        ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(reservedField), reservedField)};
-        <#break>
-    <#case "simple">
-        <#assign simpleField = field.asSimpleField().orElseThrow()>
-
-        // Simple Field (${simpleField.name})
-        ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${simpleField.name?cap_first}();
-        <#if helper.isSimpleTypeReference(simpleField.type)>
-            <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
-            <#if helper.isEnumField(field)>
-        // enum based simple field with type ${simpleField.type.asComplexTypeReference().orElseThrow().name}
-        ${helper.getWriteBufferWriteMethodCall(simpleField.type.asComplexTypeReference().orElseThrow().name, simpleTypeReference, "(" + simpleField.name + ")", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
-            <#else>
-        ${helper.getWriteBufferWriteMethodCall(simpleField.name, simpleTypeReference, "(" + simpleField.name + ")", simpleField)};
-            </#if>
-        <#else>
-        writeBuffer.pushContext("${simpleField.name}");
-            <#assign complexTypeReference = simpleField.type>
-            <#if helper.isEnumField(field)>
-        // enum field with type ${complexTypeReference.name}
-        ${helper.getWriteBufferWriteMethodCall(complexTypeReference.name, helper.getEnumBaseTypeReference(simpleField.type), "(" + simpleField.name + ".getValue())", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
-            <#else>
-        ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${simpleField.name});
-            </#if>
-        writeBuffer.popContext("${simpleField.name}");
-        </#if>
-        <#break>
-    <#case "switch">
-        <#assign switchField = field.asSwitchField().orElseThrow()>
-
-        // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
-        <#list switchField.cases as case>
-        if(_value instanceof ${case.name}) {
-            ${case.name}IO.staticSerialize(writeBuffer, (${case.name}) _value);
-        }<#sep> else </#sep>
-        </#list>
-        <#break>
-    <#case "virtual">
-        <#break>
-</#switch>
-</#list>
-        writeBuffer.popContext("${type.name}");
-    </#if>
-    }
-</#if>
-
-<#if type.isDiscriminatedParentTypeDefinition()>
-    public static interface ${type.name}Builder {
-        ${type.name} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>);
-    }
-
-</#if>
-<#if type.isDiscriminatedChildTypeDefinition()>
-    public static class ${type.name}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 ${type.name}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 ${type.name} build(<#list type.parentType.asComplexTypeDefinition().orElseThrow().propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
-            return new ${type.name}(<#list type.allPropertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        }
-    }
-
-</#if>
-}
-</#outputformat>
diff --git a/code-generation/language-java-ng/pom.xml b/code-generation/language-java-old/pom.xml
similarity index 87%
rename from code-generation/language-java-ng/pom.xml
rename to code-generation/language-java-old/pom.xml
index f3d888b..769708b 100644
--- a/code-generation/language-java-ng/pom.xml
+++ b/code-generation/language-java-old/pom.xml
@@ -27,9 +27,9 @@
     <version>0.10.0-SNAPSHOT</version>
   </parent>
 
-  <artifactId>plc4x-code-generation-language-java-ng</artifactId>
+  <artifactId>plc4x-code-generation-language-java-old</artifactId>
 
-  <name>Code-Generation: Language: Java NG</name>
+  <name>Code-Generation: Language: Java Old</name>
   <description>Code generation template for generating Java code</description>
 
   <build>
@@ -64,6 +64,13 @@
               <projectsDirectory>src/test/resources</projectsDirectory>
               <cloneProjectsTo>${project.build.directory}/integration-tests</cloneProjectsTo>
               <settingsFile>src/test/resources/settings.xml</settingsFile>
+              <extraArtifacts>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-language-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-maven-plugin:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-protocol-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+              </extraArtifacts>
               <pomIncludes>
                 <pomInclude>*/pom.xml</pomInclude>
               </pomIncludes>
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java b/code-generation/language-java-old/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
similarity index 100%
copy from code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
copy to code-generation/language-java-old/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java-old/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
similarity index 100%
copy from code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
copy to code-generation/language-java-old/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
diff --git a/code-generation/language-java-ng/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput b/code-generation/language-java-old/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
similarity index 100%
rename from code-generation/language-java-ng/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
rename to code-generation/language-java-old/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/data-io-template.java.ftlh b/code-generation/language-java-old/src/main/resources/templates/java/data-io-template.java.ftlh
similarity index 100%
rename from code-generation/language-java-ng/src/main/resources/templates/java/data-io-template.java.ftlh
rename to code-generation/language-java-old/src/main/resources/templates/java/data-io-template.java.ftlh
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/enum-package-info-template.java.ftlh b/code-generation/language-java-old/src/main/resources/templates/java/enum-package-info-template.java.ftlh
similarity index 100%
rename from code-generation/language-java-ng/src/main/resources/templates/java/enum-package-info-template.java.ftlh
rename to code-generation/language-java-old/src/main/resources/templates/java/enum-package-info-template.java.ftlh
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/enum-template.java.ftlh b/code-generation/language-java-old/src/main/resources/templates/java/enum-template.java.ftlh
similarity index 100%
rename from code-generation/language-java-ng/src/main/resources/templates/java/enum-template.java.ftlh
rename to code-generation/language-java-old/src/main/resources/templates/java/enum-template.java.ftlh
diff --git a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java-old/src/main/resources/templates/java/io-template.java.ftlh
similarity index 100%
copy from code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
copy to code-generation/language-java-old/src/main/resources/templates/java/io-template.java.ftlh
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/pojo-template.java.ftlh b/code-generation/language-java-old/src/main/resources/templates/java/pojo-template.java.ftlh
similarity index 100%
rename from code-generation/language-java-ng/src/main/resources/templates/java/pojo-template.java.ftlh
rename to code-generation/language-java-old/src/main/resources/templates/java/pojo-template.java.ftlh
diff --git a/code-generation/language-java-ng/src/test/resources/integration-test/pom.xml b/code-generation/language-java-old/src/test/resources/integration-test/pom.xml
similarity index 98%
rename from code-generation/language-java-ng/src/test/resources/integration-test/pom.xml
rename to code-generation/language-java-old/src/test/resources/integration-test/pom.xml
index cd7b509..f988928 100644
--- a/code-generation/language-java-ng/src/test/resources/integration-test/pom.xml
+++ b/code-generation/language-java-old/src/test/resources/integration-test/pom.xml
@@ -107,7 +107,7 @@
         <artifactId>maven-dependency-plugin</artifactId>
         <configuration>
           <usedDependencies combine.children="append">
-            <usedDependency>org.apache.plc4x:plc4x-code-generation-language-java</usedDependency>
+            <usedDependency>org.apache.plc4x:plc4x-code-generation-language-java-old</usedDependency>
             <usedDependency>org.apache.plc4x:plc4x-code-generation-protocol-test</usedDependency>
           </usedDependencies>
         </configuration>
@@ -180,7 +180,7 @@
 
     <dependency>
       <groupId>org.apache.plc4x</groupId>
-      <artifactId>plc4x-code-generation-language-java-ng</artifactId>
+      <artifactId>plc4x-code-generation-language-java-old</artifactId>
       <version>@project.version@</version>
       <!-- Scope is 'provided' as this way it's not shipped with the driver -->
       <scope>provided</scope>
diff --git a/code-generation/language-java-ng/src/test/resources/settings.xml b/code-generation/language-java-old/src/test/resources/settings.xml
similarity index 100%
rename from code-generation/language-java-ng/src/test/resources/settings.xml
rename to code-generation/language-java-old/src/test/resources/settings.xml
diff --git a/code-generation/language-java/pom.xml b/code-generation/language-java/pom.xml
index 1f73cb6..fcbe988 100644
--- a/code-generation/language-java/pom.xml
+++ b/code-generation/language-java/pom.xml
@@ -64,6 +64,13 @@
               <projectsDirectory>src/test/resources</projectsDirectory>
               <cloneProjectsTo>${project.build.directory}/integration-tests</cloneProjectsTo>
               <settingsFile>src/test/resources/settings.xml</settingsFile>
+              <extraArtifacts>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-language-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-maven-plugin:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-protocol-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
+              </extraArtifacts>
               <pomIncludes>
                 <pomInclude>*/pom.xml</pomInclude>
               </pomIncludes>
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
index f935fcc..f01fca1 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
@@ -18,24 +18,27 @@
  */
 package org.apache.plc4x.language.java;
 
+import com.google.googlejavaformat.java.Formatter;
 import com.google.googlejavaformat.java.FormatterException;
-import freemarker.template.*;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
 import org.apache.commons.io.FileUtils;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
 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.TypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
 import java.util.*;
 
-import com.google.googlejavaformat.java.Formatter;
-
 public class JavaLanguageOutput extends FreemarkerLanguageOutput {
 
-    private Formatter formatter = new Formatter();
+    private static final Logger LOGGER = LoggerFactory.getLogger(JavaLanguageOutput.class);
+
+    private final Formatter formatter = new Formatter();
 
     @Override
     public String getName() {
@@ -94,7 +97,7 @@ public class JavaLanguageOutput extends FreemarkerLanguageOutput {
                 StandardCharsets.UTF_8
             );
         } catch (IOException | FormatterException e) {
-            throw new RuntimeException(e);
+            LOGGER.error("Error formatting {}", outputFile, e);
         }
     }
 }
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 525dc9c..1a205ec 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -60,19 +60,18 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
 
     @Override
     public String getLanguageTypeNameForField(Field field) {
-        boolean optional = field instanceof OptionalField;
         // If the referenced type is a DataIo type, the value is of type PlcValue.
-        if (field instanceof PropertyField) {
-            PropertyField propertyField = (PropertyField) field;
-            if (propertyField.getType() instanceof ComplexTypeReference) {
-                ComplexTypeReference complexTypeReference = (ComplexTypeReference) propertyField.getType();
+        if (field.isPropertyField()) {
+            PropertyField propertyField = field.asPropertyField().orElseThrow(IllegalStateException::new);
+            if (propertyField.getType().isComplexTypeReference()) {
+                ComplexTypeReference complexTypeReference = propertyField.getType().asComplexTypeReference().orElseThrow(IllegalStateException::new);
                 final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
                 if (typeDefinition instanceof DataIoTypeDefinition) {
                     return "PlcValue";
                 }
             }
         }
-        return getLanguageTypeNameForTypeReference(((TypedField) field).getType(), !optional);
+        return getLanguageTypeNameForTypeReference(((TypedField) field).getType(), !field.isOptionalField());
     }
 
     public String getNonPrimitiveLanguageTypeNameForField(TypedField field) {
@@ -309,19 +308,21 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         }
     }
 
+    @Deprecated
     @Override
     public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
-        return getReadBufferReadMethodCall("", simpleTypeReference, valueString, field);
+        return "/*TODO: migrate me*/"+getReadBufferReadMethodCall("", simpleTypeReference, valueString, field);
     }
 
+    @Deprecated
     public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
         switch (simpleTypeReference.getBaseType()) {
             case BIT:
                 String bitType = "Bit";
-                return "readBuffer.read" + bitType + "(\"" + logicalName + "\")";
+                return "/*TODO: migrate me*/"+"readBuffer.read" + bitType + "(\"" + logicalName + "\")";
             case BYTE:
                 String byteType = "Byte";
-                return "readBuffer.read" + byteType + "(\"" + logicalName + "\")";
+                return "/*TODO: migrate me*/"+"readBuffer.read" + byteType + "(\"" + logicalName + "\")";
             case UINT:
                 String unsignedIntegerType;
                 IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
@@ -336,7 +337,7 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
                 } else {
                     unsignedIntegerType = "UnsignedBigInteger";
                 }
-                return "readBuffer.read" + unsignedIntegerType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
+                return "/*TODO: migrate me*/"+"readBuffer.read" + unsignedIntegerType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
             case INT:
                 String integerType;
                 if (simpleTypeReference.getSizeInBits() <= 8) {
@@ -350,17 +351,62 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
                 } else {
                     integerType = "BigInteger";
                 }
-                return "readBuffer.read" + integerType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
+                return "/*TODO: migrate me*/"+"readBuffer.read" + integerType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
             case FLOAT:
                 String floatType = (simpleTypeReference.getSizeInBits() <= 32) ? "Float" : "Double";
-                return "readBuffer.read" + floatType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
+                return "/*TODO: migrate me*/"+"readBuffer.read" + floatType + "(\"" + logicalName + "\", " + simpleTypeReference.getSizeInBits() + ")";
             case STRING:
             case VSTRING:
                 String stringType = "String";
                 StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return "readBuffer.read" + stringType + "(\"" + logicalName + "\", " + toParseExpression(field, stringTypeReference.getLengthExpression(), null) + ", \"" +
+                return "/*TODO: migrate me*/"+"readBuffer.read" + stringType + "(\"" + logicalName + "\", " + toParseExpression(field, stringTypeReference.getLengthExpression(), null) + ", \"" +
                     stringTypeReference.getEncoding() + "\")";
         }
+        return "/*TODO: migrate me*/"+"";
+    }
+
+    public String getDataReaderCall(TypeReference typeReference) {
+        if (isEnumTypeReference(typeReference)) {
+            final String languageTypeName = getLanguageTypeNameForTypeReference(typeReference);
+            final SimpleTypeReference enumBaseTypeReference = getEnumBaseTypeReference(typeReference);
+            return "new DataReaderEnumDefault(" + languageTypeName + "::enumForValue, " + getDataReaderCall(enumBaseTypeReference) + ")";
+        } else if (typeReference.isSimpleTypeReference()) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            return getDataReaderCall(simpleTypeReference);
+        } else if (typeReference.isComplexTypeReference()) {
+            return "new DataReaderComplex(readBuffer)";
+        } else {
+            throw new IllegalStateException("What is this type? " + typeReference);
+        }
+    }
+
+    public String getDataReaderCall(SimpleTypeReference simpleTypeReference) {
+        final int sizeInBits = simpleTypeReference.getSizeInBits();
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT:
+                return "readBoolean(readBuffer)";
+            case BYTE:
+                return "readByte(readBuffer, " + sizeInBits + ")";
+            case UINT:
+                if (sizeInBits <= 4) return "readUnsignedByte(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 8) return "readUnsignedShort(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 16) return "readUnsignedInt(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 32) return "readUnsignedLong(readBuffer, " + sizeInBits + ")";
+                return "readUnsignedBigInteger(readBuffer, " + sizeInBits + ")";
+            case INT:
+                if (sizeInBits <= 8) return "readSignedByte(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 16) return "readSignedShort(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 32) return "readSignedInt(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 64) return "readSignedLong(readBuffer, " + sizeInBits + ")";
+                return "readSignedBigInteger(readBuffer, " + sizeInBits + ")";
+            case FLOAT:
+                if (sizeInBits <= 32) return "readFloat(readBuffer, " + sizeInBits + ")";
+                if (sizeInBits <= 64) return "readDouble(readBuffer, " + sizeInBits + ")";
+                return "readBigDecimal(readBuffer, " + sizeInBits + ")";
+            case STRING:
+            case VSTRING:
+                return "readString(readBuffer, " + sizeInBits + ")";
+        }
         return "";
     }
 
diff --git a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
index ac31675..6e24051 100644
--- a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -51,6 +51,11 @@ import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
 <#if helper.getComplexTypeReferences()?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if>
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
+
+import org.apache.plc4x.java.spi.codegen.fields.*;
+import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
+import org.apache.plc4x.java.spi.codegen.io.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.spi.generation.*;
 import org.apache.plc4x.java.api.value.PlcValue;
@@ -313,17 +318,11 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#break>
     <#case "const">
         <#assign constField = field.asConstField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
 
-        // Const Field (${constField.name})
-        <#if helper.isSimpleTypeReference(constField.type)>
-            <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
-        ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.name, simpleTypeReference, "", constField)};
-        <#else>
-        ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(constField.name, helper.getEnumBaseTypeReference(constField.type), "", constField)});
-        </#if>
-        if(${constField.name} != ${type.name}.${constField.name?upper_case}) {
-            throw new ParseException("Expected constant value " + ${type.name}.${constField.name?upper_case} + " but got " + ${constField.name});
-        }
+        // ${field.typeName?cap_first} Field (${namedField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${type.name}.${namedField.name?upper_case});
         <#break>
     <#case "discriminator">
         <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
@@ -366,10 +365,11 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#break>
     <#case "implicit">
         <#assign implicitField = field.asImplicitField().orElseThrow()>
-        <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
 
-        // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = ${helper.getReadBufferReadMethodCall(implicitField.name, simpleTypeReference, "", implicitField)};
+        // ${field.typeName?cap_first} Field (${namedField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)});
         <#break>
     <#case "manualArray">
         <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
@@ -496,46 +496,20 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#if optionalField.conditionExpression.present>
         }
         </#if>
+            if (1 == 2) {
+                throw new ParseAssertException("oh no java");
+            }
         } catch(ParseAssertException ignore){
             readBuffer.reset(curPos);
         }
         <#break>
     <#case "assert">
         <#assign assertField = field.asAssertField().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
+        <#assign namedField = field.asNamedField().orElseThrow()>
 
-        // Assert Field
-        <#if helper.isEnumField(assertField)>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getLanguageTypeNameForField(assertField)}.enumForValue(${helper.getReadBufferReadMethodCall(assertField.name, helper.getEnumBaseTypeReference(simpleTypeReference), "", assertField)});
-        <#elseif helper.isComplexTypeReference(assertField.type)>
-            <#assign complexTypeReference=assertField.type.asComplexTypeReference().orElseThrow()>
-            <#assign typeName=complexTypeReference.name>
-            <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
-            <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
-                <#assign typeName=typeDefinition.getParentType().name>
-            </#if>
-            <@compress single_line=true>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = (${complexTypeReference.name}) ${typeName}IO.staticParse(readBuffer
-                <#if field.params.isPresent()>
-                    ,
-                    <#list field.params.orElseThrow() as parserArgument>
-                        (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
-                        (${helper.toParseExpression(assertField, parserArgument, parserArguments)})<#sep>, </#sep>
-                    </#list>
-                </#if>
-                <#if complexTypeReference.params.isPresent()>
-                    ,
-                    <#list complexTypeReference.params.orElseThrow() as typeParam>
-                        ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
-                    </#list>
-                </#if>);
-            </...@compress>
-        <#else>
-            <#assign simpleTypeReference = assertField.type.asSimpleTypeReference().orElseThrow()>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getReadBufferReadMethodCall(assertField.name, simpleTypeReference.asSimpleTypeReference().orElseThrow(), "", assertField)};
-        </#if>
-        if(${assertField.name} != ${helper.toParseExpression(assertField.asTypedField().orElseThrow(), assertField.conditionExpression, parserArguments)}) {
-            throw new ParseAssertException("assertField ${assertField.name} with value " + ${assertField.name} + " didn't match the expected value " + ${helper.toParseExpression(assertField, assertField.conditionExpression, parserArguments)});
-        }
+        // ${field.typeName?cap_first} Field (${namedField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${type.name}.${namedField.name?upper_case});
         <#break>
     <#case "padding">
         <#assign paddingField = field.asPaddingField().orElseThrow()>
@@ -547,22 +521,17 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)});
             while ((readBuffer.hasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding-- > 0)) {
                 // Just read the padding data and ignore it
-                ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)};
+                Object ignore = ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)};
             }
             readBuffer.closeContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "reserved">
         <#assign reservedField = field.asReservedField().orElseThrow()>
-        <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
 
-        // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
-        {
-            ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall("reserved", simpleTypeReference, "", reservedField)};
-            if(reserved != ${helper.getReservedValue(reservedField)}) {
-                LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field.");
-            }
-        }
+        // ${field.typeName?cap_first} Field
+        read${field.typeName?cap_first}Field("reserved", ${helper.getDataReaderCall(typedField.type)}, ${helper.getReservedValue(reservedField)});
         <#break>
     <#case "simple">
         <#assign simpleField = field.asSimpleField().orElseThrow()>
@@ -671,12 +640,11 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 
     <#case "unknown">
         <#assign unknownField = field.asUnknownField().orElseThrow()>
-        <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
+        <#assign typedField = field.asTypedField().orElseThrow()>
 
-        // Unknown Field
-        ${helper.getReadBufferReadMethodCall("unknown" , simpleTypeReference, "", unknownField)};
+        // ${field.typeName?cap_first} Field
+        read${field.typeName?cap_first}Field("unknown", ${helper.getDataReaderCall(typedField.type)});
         <#break>
-
     <#case "virtual">
         <#assign virtualField = field.asVirtualField().orElseThrow()>
 
diff --git a/code-generation/pom.xml b/code-generation/pom.xml
index be95f65..0a3b2dd 100644
--- a/code-generation/pom.xml
+++ b/code-generation/pom.xml
@@ -39,7 +39,7 @@
     <module>protocol-test</module>
 
     <module>language-java</module>
-    <module>language-java-ng</module>
+    <module>language-java-old</module>
   </modules>
 
   <profiles>
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
index 4962ffb..b483a0a 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
@@ -47,4 +47,17 @@ public class FieldReaderFactory {
     public static <T> T readDiscriminatorField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
         return new FieldReaderDiscriminator<T>().readField(logicalName, dataReader, readerArgs);
     }
+
+    public static <T> T readImplicitField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+        return new FieldReaderImplicit<T>().readField(logicalName, dataReader, readerArgs);
+    }
+
+    public static <T> T readReservedField(String logicalName, DataReader<T> dataReader, T expectedValue, WithReaderArgs... readerArgs) throws ParseException {
+        return new FieldReaderReserved<T>().readReservedField(logicalName, dataReader, expectedValue, readerArgs);
+    }
+
+    public static <T> T readUnknownField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+        return new FieldReaderUnknown<T>().readUnknownField(logicalName, dataReader, readerArgs);
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java
index fbb262f..ad4652d 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java
@@ -19,7 +19,6 @@
 package org.apache.plc4x.java.spi.codegen.fields;
 
 import org.apache.plc4x.java.spi.codegen.io.DataReader;
-import org.apache.plc4x.java.spi.generation.ParseAssertException;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 import org.slf4j.Logger;
@@ -36,7 +35,7 @@ public class FieldReaderReserved<T> implements FieldReader<T> {
         throw new IllegalStateException("not possible with reserved field");
     }
 
-    public T readAssertField(String logicalName, DataReader<T> dataReader, T referenceValue, WithReaderArgs... readerArgs) throws ParseException {
+    public T readReservedField(String logicalName, DataReader<T> dataReader, T referenceValue, WithReaderArgs... readerArgs) throws ParseException {
         T reserved = dataReader.read(logicalName, readerArgs);
         if (!Objects.equals(reserved, referenceValue)) {
             LOGGER.info("Expected constant value {} but got {} for reserved field.", referenceValue, reserved);
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java
index ed1a081..9e899cf 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java
@@ -33,9 +33,10 @@ public class FieldReaderUnknown<T> implements FieldReader<T> {
         throw new IllegalStateException("not possible with unknown field");
     }
 
-    public void readUnknownField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+    public T readUnknownField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
         T unknownValue = dataReader.read(logicalName, readerArgs);
-        LOGGER.debug("Read unkown value {}", unknownValue);
+        LOGGER.debug("Read unknown value {}", unknownValue);
+        return unknownValue;
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java
index 01435a2..4c30cad 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java
@@ -24,60 +24,60 @@ import java.math.BigInteger;
 
 public class DataReaderFactory {
 
-    public static DataReader<Boolean>  readBoolean(ReadBuffer readBuffer) {
+    public static DataReader<Boolean> readBoolean(ReadBuffer readBuffer) {
         return new DataReaderSimpleBoolean(readBuffer);
     }
 
-    public static DataReader<Byte> readUnsignedByte(ReadBuffer readBuffer) {
-        return new DataReaderSimpleUnsignedByte(readBuffer);
+    public static DataReader<Byte> readUnsignedByte(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleUnsignedByte(readBuffer, bitLength);
     }
 
-    public static DataReader<Short> readUnsignedShort(ReadBuffer readBuffer) {
-        return new DataReaderSimpleUnsignedShort(readBuffer);
+    public static DataReader<Short> readUnsignedShort(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleUnsignedShort(readBuffer, bitLength);
     }
 
-    public static DataReader<Integer> readUnsignedInt(ReadBuffer readBuffer) {
-        return new DataReaderSimpleUnsignedInt(readBuffer);
+    public static DataReader<Integer> readUnsignedInt(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleUnsignedInt(readBuffer, bitLength);
     }
 
-    public static DataReader<Long> readUnsignedLong(ReadBuffer readBuffer) {
-        return new DataReaderSimpleUnsignedLong(readBuffer);
+    public static DataReader<Long> readUnsignedLong(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleUnsignedLong(readBuffer, bitLength);
     }
 
-    public static DataReader<BigInteger> readUnsignedBigInteger(ReadBuffer readBuffer) {
-        return new DataReaderSimpleUnsignedBigInteger(readBuffer);
+    public static DataReader<BigInteger> readUnsignedBigInteger(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleUnsignedBigInteger(readBuffer, bitLength);
     }
 
-    public static DataReader<Byte> readSignedByte(ReadBuffer readBuffer) {
-        return new DataReaderSimpleSignedByte(readBuffer);
+    public static DataReader<Byte> readSignedByte(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleSignedByte(readBuffer, bitLength);
     }
 
-    public static DataReader<Short> readSignedShort(ReadBuffer readBuffer) {
-        return new DataReaderSimpleSignedShort(readBuffer);
+    public static DataReader<Short> readSignedShort(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleSignedShort(readBuffer, bitLength);
     }
 
-    public static DataReader<Integer> readSignedInt(ReadBuffer readBuffer) {
-        return new DataReaderSimpleSignedInt(readBuffer);
+    public static DataReader<Integer> readSignedInt(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleSignedInt(readBuffer, bitLength);
     }
 
-    public static DataReader<Long> readSignedLong(ReadBuffer readBuffer) {
-        return new DataReaderSimpleSignedLong(readBuffer);
+    public static DataReader<Long> readSignedLong(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleSignedLong(readBuffer, bitLength);
     }
 
-    public static DataReader<BigInteger> readSignedBigInteger(ReadBuffer readBuffer) {
-        return new DataReaderSimpleSignedBigInteger(readBuffer);
+    public static DataReader<BigInteger> readSignedBigInteger(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleSignedBigInteger(readBuffer, bitLength);
     }
 
-    public static DataReader<Float> readFloat(ReadBuffer readBuffer) {
-        return new DataReaderSimpleFloat(readBuffer);
+    public static DataReader<Float> readFloat(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleFloat(readBuffer, bitLength);
     }
 
-    public static DataReader<Double> readDouble(ReadBuffer readBuffer) {
-        return new DataReaderSimpleDouble(readBuffer);
+    public static DataReader<Double> readDouble(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleDouble(readBuffer, bitLength);
     }
 
-    public static DataReader<String > readString(ReadBuffer readBuffer) {
-        return new DataReaderSimpleString(readBuffer);
+    public static DataReader<String> readString(ReadBuffer readBuffer, int bitLength) {
+        return new DataReaderSimpleString(readBuffer, bitLength);
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java
index dda35e6..b370cf8 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java
@@ -18,14 +18,6 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
-import org.apache.plc4x.java.spi.generation.*;
-
 public interface DataReaderSimple<T> extends DataReader<T> {
 
-    default T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
-        throw new IllegalStateException(DataReaderSimple.class.getSimpleName() + " can't be called without a bit length");
-    }
-
-    T read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
-
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java
index 588f050..ccf3789 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java
@@ -25,13 +25,15 @@ import java.math.BigDecimal;
 public class DataReaderSimpleBigDecimal implements DataReaderSimple<BigDecimal> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleBigDecimal(ReadBuffer readBuffer) {
+    public DataReaderSimpleBigDecimal(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public BigDecimal read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+    public BigDecimal read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         return readBuffer.readBigDecimal(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java
index cb82d0a..4d4f9ec 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java
@@ -18,7 +18,10 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
-import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
 import java.util.Objects;
 
@@ -31,10 +34,7 @@ public class DataReaderSimpleBoolean implements DataReaderSimple<Boolean> {
     }
 
     @Override
-    public Boolean read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
-        if(bitLength != 1) {
-            throw new ParseException("Bit fields only support bitLength of 1");
-        }
+    public Boolean read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         return readBuffer.readBit(logicalName, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java
index decf526..d5f9b7a 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleByte implements DataReaderSimple<Byte> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleByte(ReadBuffer readBuffer) {
+    public DataReaderSimpleByte(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Byte read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Byte read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         if(bitLength != 8) {
             throw new ParseException("Byte fields only support bitLength of 8");
         }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java
index 393808e..d3d32b2 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java
@@ -18,22 +18,28 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
-import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
 public class DataReaderSimpleByteArray implements DataReaderSimple<byte[]> {
 
     private final ReadBuffer readBuffer;
 
-    public DataReaderSimpleByteArray(ReadBuffer readBuffer) {
+    private final int bitLength;
+
+    public DataReaderSimpleByteArray(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public byte[] read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+    public byte[] read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         if (bitLength % 8 != 0) {
             throw new ParseException("ByteArray fields only support bitLength which are multiples of 8");
         }
-        return readBuffer.readByteArray(logicalName, bitLength * 8, readerArgs);
+        return readBuffer.readByteArray(logicalName, bitLength / 8, readerArgs);
     }
 
     public int getPos() {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java
index ef05617..08b52dc 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleDouble implements DataReaderSimple<Double> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleDouble(ReadBuffer readBuffer) {
+    public DataReaderSimpleDouble(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Double read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Double read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readDouble(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java
index 9da8b45..45576f3 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleFloat implements DataReaderSimple<Float> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleFloat(ReadBuffer readBuffer) {
+    public DataReaderSimpleFloat(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Float read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Float read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readFloat(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java
index ce4d59a..2d41818 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java
@@ -25,13 +25,15 @@ import java.math.BigInteger;
 public class DataReaderSimpleSignedBigInteger implements DataReaderSimple<BigInteger> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleSignedBigInteger(ReadBuffer readBuffer) {
+    public DataReaderSimpleSignedBigInteger(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public BigInteger read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public BigInteger read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readBigInteger(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java
index 50fd661..93f8875 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleSignedByte implements DataReaderSimple<Byte> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleSignedByte(ReadBuffer readBuffer) {
+    public DataReaderSimpleSignedByte(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Byte read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Byte read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readSignedByte(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java
index 005c1e8..25a46b6 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleSignedInt implements DataReaderSimple<Integer> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleSignedInt(ReadBuffer readBuffer) {
+    public DataReaderSimpleSignedInt(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Integer read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Integer read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readInt(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java
index 804cea8..6992b34 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleSignedLong implements DataReaderSimple<Long> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleSignedLong(ReadBuffer readBuffer) {
+    public DataReaderSimpleSignedLong(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Long read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Long read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readLong(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java
index 39cd4fb..eecc653 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleSignedShort implements DataReaderSimple<Short> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleSignedShort(ReadBuffer readBuffer) {
+    public DataReaderSimpleSignedShort(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Short read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Short read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readShort(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleString.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleString.java
index facbd80..00ce5a1 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleString.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleString.java
@@ -26,13 +26,15 @@ import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 public class DataReaderSimpleString implements DataReaderSimple<String> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleString(ReadBuffer readBuffer) {
+    public DataReaderSimpleString(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public String read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public String read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         return readBuffer.readString(logicalName, bitLength, "UTF-8", readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java
index dad1744..f51b89d 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java
@@ -18,20 +18,25 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
-import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
 import java.math.BigInteger;
 
 public class DataReaderSimpleUnsignedBigInteger implements DataReaderSimple<BigInteger> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleUnsignedBigInteger(ReadBuffer readBuffer) {
+    public DataReaderSimpleUnsignedBigInteger(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public BigInteger read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public BigInteger read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         return readBuffer.readUnsignedBigInteger(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java
index 2b620bb..b2ed56d 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleUnsignedByte implements DataReaderSimple<Byte> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleUnsignedByte(ReadBuffer readBuffer) {
+    public DataReaderSimpleUnsignedByte(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Byte read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Byte read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readUnsignedByte(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java
index 3342ddb..0d3ce80 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleUnsignedInt implements DataReaderSimple<Integer> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleUnsignedInt(ReadBuffer readBuffer) {
+    public DataReaderSimpleUnsignedInt(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Integer read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Integer read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readUnsignedInt(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
index d1cc2e9..efe687a 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
@@ -23,13 +23,15 @@ import org.apache.plc4x.java.spi.generation.*;
 public class DataReaderSimpleUnsignedLong implements DataReaderSimple<Long> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleUnsignedLong(ReadBuffer readBuffer) {
+    public DataReaderSimpleUnsignedLong(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Long read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException  {
+    public Long read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
         return readBuffer.readUnsignedLong(logicalName, bitLength, readerArgs);
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java
index e52a606..3643d6a 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java
@@ -18,18 +18,23 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
-import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
 public class DataReaderSimpleUnsignedShort implements DataReaderSimple<Short> {
 
     private final ReadBuffer readBuffer;
+    private final int bitLength;
 
-    public DataReaderSimpleUnsignedShort(ReadBuffer readBuffer) {
+    public DataReaderSimpleUnsignedShort(ReadBuffer readBuffer, int bitLength) {
         this.readBuffer = readBuffer;
+        this.bitLength = bitLength;
     }
 
     @Override
-    public Short read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+    public Short read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
         return readBuffer.readUnsignedShort(logicalName, bitLength, readerArgs);
     }