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

[plc4x] branch feature/c-code-generation-tagged-unions updated: - Backported the major changes in the C code-generation back to the java version - Introduced a BaseFreemarkerLanguageTemplateHelper which contains methods usable for multiple code generations - Updated the mspec definitions to now use the discriminators directly

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

cdutz pushed a commit to branch feature/c-code-generation-tagged-unions
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/c-code-generation-tagged-unions by this push:
     new 6843ffd  - Backported the major changes in the C code-generation back to the java version - Introduced a BaseFreemarkerLanguageTemplateHelper which contains methods usable for multiple code generations - Updated the mspec definitions to now use the discriminators directly
6843ffd is described below

commit 6843ffd39d63311f5ba0eb2e50f425c32d343720
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Jun 15 11:28:59 2020 +0200

    - Backported the major changes in the C code-generation back to the java version
    - Introduced a BaseFreemarkerLanguageTemplateHelper which contains methods usable for multiple code generations
    - Updated the mspec definitions to now use the discriminators directly
---
 .../BaseFreemarkerLanguageTemplateHelper.java      | 179 +++++++--
 .../plc4x/language/c/CLanguageTemplateHelper.java  | 120 +++---
 .../main/resources/templates/c/enum-template.ftlh  |   2 +-
 .../resources/templates/c/pojo-template-c.ftlh     | 197 ++++++----
 .../resources/templates/c/pojo-template-h.ftlh     |  32 +-
 .../language/java/JavaLanguageTemplateHelper.java  | 172 ++-------
 .../resources/templates/java/data-io-template.ftlh |  94 +++--
 .../templates/java/enum-package-info-template.ftlh |   8 +
 .../resources/templates/java/enum-template.ftlh    |  39 +-
 .../main/resources/templates/java/io-template.ftlh | 426 ++++++++++++---------
 .../resources/templates/java/pojo-template.ftlh    | 237 ++++++++----
 .../apache/plc4x/java/s7/utils/StaticHelper.java   |   6 +-
 .../eip/src/main/resources/protocols/eip/eip.mspec |   4 +-
 .../main/resources/protocols/firmata/firmata.mspec |   4 +-
 .../resources/protocols/knxnetip/knxnetip.mspec    |   4 +-
 .../main/resources/protocols/modbus/modbus.mspec   |   4 +-
 .../generated-sources/modbus/includes/modbus_pdu.h |  39 +-
 .../modbus/src/modbus_constants.c                  |   2 +-
 .../generated-sources/modbus/src/modbus_pdu.c      |  78 ++--
 .../src/modbus_pdu_read_file_record_request_item.c |   2 +-
 .../modbus_pdu_read_file_record_response_item.c    |   2 +-
 .../modbus_pdu_write_file_record_request_item.c    |   2 +-
 .../modbus_pdu_write_file_record_response_item.c   |   2 +-
 .../modbus/src/modbus_serial_adu.c                 |   8 +-
 .../generated-sources/modbus/src/modbus_tcp_adu.c  |   2 +-
 .../generated-sources/s7/includes/cotp_packet.h    |   9 +-
 .../generated-sources/s7/includes/cotp_parameter.h |   4 -
 .../generated-sources/s7/includes/s7_address.h     |   2 +-
 .../generated-sources/s7/includes/s7_message.h     |   5 +-
 .../generated-sources/s7/includes/s7_parameter.h   |   6 -
 .../generated-sources/s7/includes/s7_payload.h     |  14 +-
 .../s7/includes/s7_payload_user_data_item.h        |   5 +-
 .../s7/includes/s7_var_payload_data_item.h         |   2 +-
 .../generated-sources/s7/includes/transport_size.h |   2 +-
 .../plc4c/generated-sources/s7/src/cotp_packet.c   |   2 +-
 .../generated-sources/s7/src/cotp_parameter.c      |   2 +-
 .../plc4c/generated-sources/s7/src/s7_address.c    |   2 +-
 .../plc4c/generated-sources/s7/src/s7_message.c    |   8 +-
 .../plc4c/generated-sources/s7/src/s7_parameter.c  |  14 +-
 .../s7/src/s7_parameter_user_data_item.c           |   2 +-
 .../plc4c/generated-sources/s7/src/s7_payload.c    |  10 +-
 .../s7/src/s7_payload_user_data_item.c             |   2 +-
 .../s7/src/s7_var_payload_data_item.c              |   2 +-
 .../s7/src/s7_var_payload_status_item.c            |   2 +-
 .../s7/src/s7_var_request_parameter_item.c         |   2 +-
 .../generated-sources/s7/src/szl_data_tree_item.c  |   2 +-
 sandbox/plc4c/generated-sources/s7/src/szl_id.c    |   2 +-
 .../plc4c/generated-sources/s7/src/tpkt_packet.c   |   8 +-
 .../org/apache/plc4x/java/df1/util/DF1Utils.java   |   5 +-
 49 files changed, 994 insertions(+), 785 deletions(-)

diff --git a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
index 5f31929..f5ed8b7 100644
--- a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
+++ b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
@@ -104,12 +104,10 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
 
     public abstract String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference);
 
-    public abstract String getWriteBufferReadMethodCall(SimpleTypeReference simpleTypeReference);
+    public abstract String getWriteBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String fieldName);
 
     public abstract String getNullValueForTypeReference(TypeReference typeReference);
 
-    public abstract String getDiscriminatorName(Term discriminatorExpression);
-
     /* *********************************************************************************
      * Methods related to type-references.
      **********************************************************************************/
@@ -136,7 +134,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      *
      * @return Collection of all complex type references used in fields or enum constants.
      */
-    public Collection<ComplexTypeReference> getComplexTypeReferences() {
+    public Collection<String> getComplexTypeReferences() {
         return getComplexTypeReferences(thisType);
     }
 
@@ -147,14 +145,14 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * @param baseType the base type we want to get the type references from
      * @return collection of complex type references used in the type.
      */
-    public Collection<ComplexTypeReference> getComplexTypeReferences(TypeDefinition baseType) {
-        Set<ComplexTypeReference> complexTypeReferences = new HashSet<>();
+    public Collection<String> getComplexTypeReferences(TypeDefinition baseType) {
+        Set<String> complexTypeReferences = new HashSet<>();
         // If this is a subtype of a discriminated type, we have to add a reference to the parent type.
         if (baseType instanceof DiscriminatedComplexTypeDefinition) {
             DiscriminatedComplexTypeDefinition discriminatedComplexTypeDefinition = (DiscriminatedComplexTypeDefinition) baseType;
             if(!discriminatedComplexTypeDefinition.isAbstract()) {
-                complexTypeReferences.add((ComplexTypeReference)
-                    discriminatedComplexTypeDefinition.getParentType().getTypeReference());
+                complexTypeReferences.add(((ComplexTypeReference)
+                    discriminatedComplexTypeDefinition.getParentType().getTypeReference()).getName());
             }
         }
         // If it's a complex type definition, add all the types referenced by any property fields
@@ -166,7 +164,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
                     PropertyField propertyField = (PropertyField) field;
                     if (propertyField.getType() instanceof ComplexTypeReference) {
                         ComplexTypeReference complexTypeReference = (ComplexTypeReference) propertyField.getType();
-                        complexTypeReferences.add(complexTypeReference);
+                        complexTypeReferences.add(complexTypeReference.getName());
                     }
                 } else if(field instanceof SwitchField) {
                     SwitchField switchField = (SwitchField) field;
@@ -182,7 +180,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
                 final TypeReference constantType = ((EnumTypeDefinition) thisType).getConstantType(constantName);
                 if (constantType instanceof ComplexTypeReference) {
                     ComplexTypeReference complexTypeReference = (ComplexTypeReference) constantType;
-                    complexTypeReferences.add(complexTypeReference);
+                    complexTypeReferences.add(complexTypeReference.getName());
                 }
             }
         }
@@ -191,7 +189,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             for (Argument parserArgument : baseType.getParserArguments()) {
                 if (parserArgument.getType() instanceof ComplexTypeReference) {
                     ComplexTypeReference complexTypeReference = (ComplexTypeReference) parserArgument.getType();
-                    complexTypeReferences.add(complexTypeReference);
+                    complexTypeReferences.add(complexTypeReference.getName());
                 }
             }
         }
@@ -274,19 +272,27 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * Methods related to fields.
      **********************************************************************************/
 
-    public boolean isSwitchField(Field field) {
-        return field instanceof SwitchField;
+    public boolean isAbstractField(Field field) {
+        return field instanceof AbstractField;
     }
 
     public boolean isEnumField(Field field) {
         return field instanceof EnumField;
     }
 
+    public boolean isSwitchField(Field field) {
+        return field instanceof SwitchField;
+    }
+
     public boolean isCountArrayField(Field field) {
         if(field instanceof ArrayField) {
             ArrayField arrayField = (ArrayField) field;
             return arrayField.getLoopType() == ArrayField.LoopType.COUNT;
         }
+        if(field instanceof ManualArrayField) {
+            ManualArrayField arrayField = (ManualArrayField) field;
+            return arrayField.getLoopType() == ManualArrayField.LoopType.COUNT;
+        }
         return false;
     }
 
@@ -295,6 +301,10 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             ArrayField arrayField = (ArrayField) field;
             return arrayField.getLoopType() == ArrayField.LoopType.LENGTH;
         }
+        if(field instanceof ManualArrayField) {
+            ManualArrayField arrayField = (ManualArrayField) field;
+            return arrayField.getLoopType() == ManualArrayField.LoopType.LENGTH;
+        }
         return false;
     }
 
@@ -303,6 +313,10 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             ArrayField arrayField = (ArrayField) field;
             return arrayField.getLoopType() == ArrayField.LoopType.TERMINATED;
         }
+        if(field instanceof ManualArrayField) {
+            ManualArrayField arrayField = (ManualArrayField) field;
+            return arrayField.getLoopType() == ManualArrayField.LoopType.TERMINATED;
+        }
         return false;
     }
 
@@ -342,10 +356,18 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * Methods related to type-definitions.
      **********************************************************************************/
 
+    public boolean isDiscriminatedParentTypeDefinition() {
+        return isDiscriminatedParentTypeDefinition(thisType);
+    }
+
     public boolean isDiscriminatedParentTypeDefinition(TypeDefinition typeDefinition) {
         return (typeDefinition instanceof ComplexTypeDefinition) && ((ComplexTypeDefinition) typeDefinition).isAbstract();
     }
 
+    public boolean isDiscriminatedChildTypeDefinition() {
+        return isDiscriminatedChildTypeDefinition(thisType);
+    }
+
     public boolean isDiscriminatedChildTypeDefinition(TypeDefinition typeDefinition) {
         return (typeDefinition instanceof DiscriminatedComplexTypeDefinition) && !((ComplexTypeDefinition) typeDefinition).isAbstract();
     }
@@ -462,6 +484,83 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return type;
     }
 
+    /**
+     * Get an ordered list of generated names for the discriminators.
+     * These names can be used to access the type definitions as well as well as the values.
+     * @return list of symbolic names for the discriminators.
+     */
+    public List<String> getDiscriminatorNames() {
+        TypeDefinition baseType = thisType;
+        if(thisType.getParentType() != null) {
+            baseType = thisType.getParentType();
+        }
+        final SwitchField switchField = getSwitchField(baseType);
+        List<String> discriminatorNames = new ArrayList<>();
+        for (Term discriminatorExpression : switchField.getDiscriminatorExpressions()) {
+            discriminatorNames.add(getDiscriminatorName(discriminatorExpression));
+        }
+        return discriminatorNames;
+    }
+
+    /**
+     * Check if there's any field with the given name.
+     * This is required to suppress the generation of a discriminator field
+     * in case a named field is providing the information.
+     * @param discriminatorName name of the discriminator name
+     * @return true if a field with the given name already exists in the same type.
+     */
+    public boolean isNonDiscriminatorField(String discriminatorName) {
+        return ((ComplexTypeDefinition) thisType).getAllPropertyFields().stream().anyMatch(
+            field -> !(field instanceof DiscriminatorField) && field.getName().equals(discriminatorName));
+    }
+
+    /**
+     * Converts a given discriminator description into a symbolic name.
+     * @param discriminatorExpression discriminator expression
+     * @return name
+     */
+    public String getDiscriminatorName(Term discriminatorExpression) {
+        if(discriminatorExpression instanceof Literal) {
+            Literal literal = (Literal) discriminatorExpression;
+            if(literal instanceof NullLiteral) {
+                return "null";
+            } else if(literal instanceof BooleanLiteral) {
+                return Boolean.toString(((BooleanLiteral) literal).getValue());
+            } else if(literal instanceof NumericLiteral) {
+                return ((NumericLiteral) literal).getNumber().toString();
+            } else if(literal instanceof StringLiteral) {
+                return ((StringLiteral) literal).getValue();
+            } else if(literal instanceof VariableLiteral) {
+                VariableLiteral variableLiteral = (VariableLiteral) literal;
+                return getVariableLiteralName(variableLiteral);
+            }
+        } else if(discriminatorExpression instanceof UnaryTerm) {
+            UnaryTerm unaryTerm = (UnaryTerm) discriminatorExpression;
+            return getDiscriminatorName(unaryTerm.getA());
+        } else if(discriminatorExpression instanceof BinaryTerm) {
+            BinaryTerm binaryTerm = (BinaryTerm) discriminatorExpression;
+            return getDiscriminatorName(binaryTerm.getA()) + "_" + getDiscriminatorName(binaryTerm.getB());
+        } else if(discriminatorExpression instanceof TernaryTerm) {
+            TernaryTerm ternaryTerm = (TernaryTerm) discriminatorExpression;
+            return getDiscriminatorName(ternaryTerm.getA()) + "_" + getDiscriminatorName(ternaryTerm.getB())
+                + "_" + getDiscriminatorName(ternaryTerm.getC());
+        }
+        return "";
+    }
+
+    private String getVariableLiteralName(VariableLiteral variableLiteral) {
+        String rest = "";
+        if(variableLiteral.getChild() != null) {
+            rest = getVariableLiteralName(variableLiteral.getChild());
+            rest = rest.substring(0, 1).toUpperCase() + rest.substring(1);
+        }
+        return variableLiteral.getName() + rest;
+    }
+
+    /**
+     * Get a list of the types for every discriminator name.
+     * @return Map mapping discriminator names to types.
+     */
     public Map<String, TypeReference> getDiscriminatorTypes() {
         // Get the parent type (Which contains the typeSwitch field)
         ComplexTypeDefinition parentType;
@@ -485,6 +584,29 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return Collections.emptyMap();
     }
 
+    public Map<String, String> getDiscriminatorValues(TypeDefinition type) {
+        if (type instanceof DiscriminatedComplexTypeDefinition) {
+            DiscriminatedComplexTypeDefinition switchType = (DiscriminatedComplexTypeDefinition) type;
+            final List<String> discriminatorNames = getDiscriminatorNames();
+            final Map<String, String> discriminatorValues = new HashMap<>();
+            for (int i = 0; i < discriminatorNames.size(); i++) {
+                String discriminatorValue;
+                if (i < switchType.getDiscriminatorValues().length) {
+                    discriminatorValue = switchType.getDiscriminatorValues()[i];
+                } else {
+                    discriminatorValue = null;
+                }
+                discriminatorValues.put(discriminatorNames.get(i), discriminatorValue);
+            }
+            return discriminatorValues;
+        }
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Get a list of the values for every discriminator name for every discriminated type.
+     * @return Map mapping discriminator names to discriminator values for every discriminated type.
+     */
     public Map<String, Map<String, String>> getDiscriminatorValues() {
         // Get the parent type (Which contains the typeSwitch field)
         ComplexTypeDefinition parentType;
@@ -496,30 +618,29 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         // Get the typeSwitch field from that.
         final SwitchField switchField = getSwitchField(parentType);
         if (switchField != null) {
-            // Get the symbolic names of all discriminators
-            String[] discriminatorNames = new String[switchField.getDiscriminatorExpressions().length];
-            for (int i = 0; i < switchField.getDiscriminatorExpressions().length; i++) {
-                discriminatorNames[i] = getDiscriminatorName(switchField.getDiscriminatorExpressions()[i]);
-            }
             // Build a map containing the named discriminator values for every case of the typeSwitch.
             Map<String, Map<String, String>> discriminatorTypes = new TreeMap<>();
             for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
-                discriminatorTypes.put(switchCase.getName(), new TreeMap<>());
-                for (int i = 0; i < switchField.getDiscriminatorExpressions().length; i++) {
-                    String discriminatorValue;
-                    if (i < switchCase.getDiscriminatorValues().length) {
-                        discriminatorValue = switchCase.getDiscriminatorValues()[i];
-                    } else {
-                        discriminatorValue = null;
-                    }
-                    discriminatorTypes.get(switchCase.getName()).put(discriminatorNames[i], discriminatorValue);
-                }
+                discriminatorTypes.put(switchCase.getName(), getDiscriminatorValues(switchCase));
             }
             return discriminatorTypes;
         }
         return Collections.emptyMap();
     }
 
-
+    public TypeReference 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 complexTypeDefinition.getParserArguments()[index].getType();
+        }
+        throw new RuntimeException("Only complex type references supported here.");
+    }
 
 }
diff --git a/build-utils/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java b/build-utils/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
index 76642a7..416fb11 100644
--- a/build-utils/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
+++ b/build-utils/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
@@ -351,7 +351,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
     }
 
     @Override
-    public String getWriteBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
+    public String getWriteBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String fieldName) {
         return null;
     }
 
@@ -365,15 +365,15 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
 
 
 
-    public String toParseExpression(Term term, Argument[] parserArguments) {
-        return toExpression(term, term1 -> toVariableParseExpression(term1, parserArguments));
+    public String toParseExpression(Field field, Term term, Argument[] parserArguments) {
+        return toExpression(field, term, term1 -> toVariableParseExpression(field, term1, parserArguments));
     }
 
-    public String toSerializationExpression(Term term, Argument[] parserArguments) {
-        return toExpression(term, term1 -> toVariableSerializationExpression(term1, parserArguments));
+    public String toSerializationExpression(Field field, Term term, Argument[] parserArguments) {
+        return toExpression(field, term, term1 -> toVariableSerializationExpression(field, term1, parserArguments));
     }
 
-    private String toExpression(Term term, Function<Term, String> variableExpressionGenerator) {
+    private String toExpression(Field field, Term term, Function<Term, String> variableExpressionGenerator) {
         if (term == null) {
             return "";
         }
@@ -402,11 +402,11 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
             Term a = ut.getA();
             switch (ut.getOperation()) {
                 case "!":
-                    return "!(" + toExpression(a, variableExpressionGenerator) + ")";
+                    return "!(" + toExpression(field, a, variableExpressionGenerator) + ")";
                 case "-":
-                    return "-(" + toExpression(a, variableExpressionGenerator) + ")";
+                    return "-(" + toExpression(field, a, variableExpressionGenerator) + ")";
                 case "()":
-                    return "(" + toExpression(a, variableExpressionGenerator) + ")";
+                    return "(" + toExpression(field, a, variableExpressionGenerator) + ")";
                 default:
                     throw new RuntimeException("Unsupported unary operation type " + ut.getOperation());
             }
@@ -417,9 +417,9 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
             String operation = bt.getOperation();
             switch (operation) {
                 case "^":
-                    return "Math.pow((" + toExpression(a, variableExpressionGenerator) + "), (" + toExpression(b, variableExpressionGenerator) + "))";
+                    return "Math.pow((" + toExpression(field, a, variableExpressionGenerator) + "), (" + toExpression(field, b, variableExpressionGenerator) + "))";
                 default:
-                    return "(" + toExpression(a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(b, variableExpressionGenerator) + ")";
+                    return "(" + toExpression(field, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, b, variableExpressionGenerator) + ")";
             }
         } else if (term instanceof TernaryTerm) {
             TernaryTerm tt = (TernaryTerm) term;
@@ -427,7 +427,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                 Term a = tt.getA();
                 Term b = tt.getB();
                 Term c = tt.getC();
-                return "((" + toExpression(a, variableExpressionGenerator) + ") ? " + toExpression(b, variableExpressionGenerator) + " : " + toExpression(c, variableExpressionGenerator) + ")";
+                return "((" + toExpression(field, a, variableExpressionGenerator) + ") ? " + toExpression(field, b, variableExpressionGenerator) + " : " + toExpression(field, c, variableExpressionGenerator) + ")";
             } else {
                 throw new RuntimeException("Unsupported ternary operation type " + tt.getOperation());
             }
@@ -436,7 +436,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         }
     }
 
-    public String toVariableParseExpression(Term term, Argument[] parserArguments) {
+    public String toVariableParseExpression(Field field, Term term, Argument[] parserArguments) {
         VariableLiteral vl = (VariableLiteral) term;
         // Any name that is full upper-case is considered a function call.
         // These are generally defined in the spi file evaluation_helper.c.
@@ -450,7 +450,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     if (!firstArg) {
                         sb.append(", ");
                     }
-                    sb.append(toParseExpression(arg, parserArguments));
+                    sb.append(toParseExpression(field, arg, parserArguments));
                     firstArg = false;
                 }
                 sb.append(")");
@@ -513,7 +513,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         return vl.getName() + ((vl.getChild() != null) ? "." + toVariableExpressionRest(vl.getChild()) : "");
     }
 
-    private String toVariableSerializationExpression(Term term, Argument[] serialzerArguments) {
+    private String toVariableSerializationExpression(Field field, Term term, Argument[] serialzerArguments) {
         VariableLiteral vl = (VariableLiteral) term;
         if ("STATIC_CALL".equals(vl.getName())) {
             StringBuilder sb = new StringBuilder();
@@ -543,7 +543,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     }
                     if (isSerializerArg) {
                         sb.append(va.getName() + ((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : ""));
-                    } /*else if (isTypeArg) {
+                    } else if (isTypeArg) {
                         String part = va.getChild().getName();
                         switch (part) {
                             case "name":
@@ -553,14 +553,22 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                                 sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
                                 break;
                             case "encoding":
-                                String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                                if(!(field instanceof TypedField)) {
+                                    throw new RuntimeException("'encoding' only supported for typed fields.");
+                                }
+                                TypedField typedField = (TypedField) field;
+                                if(!(typedField.getType() instanceof StringTypeReference)) {
+                                    throw new RuntimeException("Can only access 'encoding' for string types.");
+                                }
+                                StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
+                                String encoding = stringTypeReference.getEncoding();
                                 // Cut off the single quotes.
                                 encoding = encoding.substring(1, encoding.length() - 1);
                                 sb.append("\"").append(encoding).append("\"");
                                 break;
                         }
-                    }*/ else {
-                        sb.append(toVariableSerializationExpression(va, null));
+                    } else {
+                        sb.append(toVariableSerializationExpression(field, va, null));
                     }
                 } else if (arg instanceof StringLiteral) {
                     sb.append(((StringLiteral) arg).getValue());
@@ -614,7 +622,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                         }
                         if (isSerializerArg) {
                             sb.append(va.getName() + ((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : ""));
-                        } /*else if (isTypeArg) {
+                        } else if (isTypeArg) {
                             String part = va.getChild().getName();
                             switch (part) {
                                 case "name":
@@ -624,14 +632,22 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                                     sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
                                     break;
                                 case "encoding":
-                                    String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                                    if(!(field instanceof TypedField)) {
+                                        throw new RuntimeException("'encoding' only supported for typed fields.");
+                                    }
+                                    TypedField typedField = (TypedField) field;
+                                    if(!(typedField.getType() instanceof StringTypeReference)) {
+                                        throw new RuntimeException("Can only access 'encoding' for string types.");
+                                    }
+                                    StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
+                                    String encoding = stringTypeReference.getEncoding();
                                     // Cut off the single quotes.
                                     encoding = encoding.substring(1, encoding.length() - 1);
                                     sb.append("\"").append(encoding).append("\"");
                                     break;
                             }
-                        }*/ else {
-                            sb.append(toVariableSerializationExpression(va, null));
+                        } else {
+                            sb.append(toVariableSerializationExpression(field, va, null));
                         }
                     } else if (arg instanceof StringLiteral) {
                         sb.append(((StringLiteral) arg).getValue());
@@ -655,7 +671,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         }
         if (isSerializerArg) {
             return vl.getName() + ((vl.getChild() != null) ? "." + toVariableExpressionRest(vl.getChild()) : "");
-        } /*else if (isTypeArg) {
+        } else if (isTypeArg) {
             String part = vl.getChild().getName();
             switch (part) {
                 case "name":
@@ -663,14 +679,22 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                 case "length":
                     return "\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
                 case "encoding":
-                    String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                    if(!(field instanceof TypedField)) {
+                        throw new RuntimeException("'encoding' only supported for typed fields.");
+                    }
+                    TypedField typedField = (TypedField) field;
+                    if(!(typedField.getType() instanceof StringTypeReference)) {
+                        throw new RuntimeException("Can only access 'encoding' for string types.");
+                    }
+                    StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
+                    String encoding = stringTypeReference.getEncoding();
                     // Cut off the single quotes.
                     encoding = encoding.substring(1, encoding.length() - 1);
                     return "\"" + encoding + "\"";
                 default:
                     return "";
             }
-        }*/ else {
+        } else {
             return "_value." + toVariableExpressionRest(vl);
         }
     }
@@ -704,48 +728,4 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         }
     }
 
-    public String getReservedValue(ReservedField reservedField) {
-        final String languageTypeName = getLanguageTypeNameForField(reservedField);
-        if ("BigInteger".equals(languageTypeName)) {
-            return "BigInteger.valueOf(" + reservedField.getReferenceValue() + ")";
-        } else {
-            return "(" + languageTypeName + ") " + reservedField.getReferenceValue();
-        }
-    }
-
-    @Override
-    public String getDiscriminatorName(Term discriminatorExpression) {
-        if(discriminatorExpression instanceof Literal) {
-            Literal literal = (Literal) discriminatorExpression;
-            if(literal instanceof NullLiteral) {
-                return "null";
-            } else if(literal instanceof BooleanLiteral) {
-                return Boolean.toString(((BooleanLiteral) literal).getValue());
-            } else if(literal instanceof NumericLiteral) {
-                return ((NumericLiteral) literal).getNumber().toString();
-            } else if(literal instanceof StringLiteral) {
-                return ((StringLiteral) literal).getValue();
-            } else if(literal instanceof VariableLiteral) {
-                VariableLiteral variableLiteral = (VariableLiteral) literal;
-                return getVariableLiteralName(variableLiteral);
-            }
-        } else if(discriminatorExpression instanceof UnaryTerm) {
-            UnaryTerm unaryTerm = (UnaryTerm) discriminatorExpression;
-            return getDiscriminatorName(unaryTerm.getA());
-        } else if(discriminatorExpression instanceof BinaryTerm) {
-            BinaryTerm binaryTerm = (BinaryTerm) discriminatorExpression;
-            return getDiscriminatorName(binaryTerm.getA()) + "_" + getDiscriminatorName(binaryTerm.getB());
-        } else if(discriminatorExpression instanceof TernaryTerm) {
-            TernaryTerm ternaryTerm = (TernaryTerm) discriminatorExpression;
-            return getDiscriminatorName(ternaryTerm.getA()) + "_" + getDiscriminatorName(ternaryTerm.getB())
-                + "_" + getDiscriminatorName(ternaryTerm.getC());
-        }
-        return "";
-    }
-
-    private String getVariableLiteralName(VariableLiteral variableLiteral) {
-        return variableLiteral.getName() + ((variableLiteral.getChild() != null) ?
-            "_" + getVariableLiteralName(variableLiteral.getChild()) : "");
-    }
-
 }
diff --git a/build-utils/language-c/src/main/resources/templates/c/enum-template.ftlh b/build-utils/language-c/src/main/resources/templates/c/enum-template.ftlh
index 35994fd..8979de9 100644
--- a/build-utils/language-c/src/main/resources/templates/c/enum-template.ftlh
+++ b/build-utils/language-c/src/main/resources/templates/c/enum-template.ftlh
@@ -48,7 +48,7 @@ extern "C" {
 -->
 <#if helper.getComplexTypeReferences()?has_content>
     <#list helper.getComplexTypeReferences() as typeReference>
-#include "${helper.camelCaseToSnakeCase(typeReference.name)}.h"
+#include "${helper.camelCaseToSnakeCase(typeReference)}.h"
     </#list>
 </#if>
 
diff --git a/build-utils/language-c/src/main/resources/templates/c/pojo-template-c.ftlh b/build-utils/language-c/src/main/resources/templates/c/pojo-template-c.ftlh
index e4952dc..6c5fe03 100644
--- a/build-utils/language-c/src/main/resources/templates/c/pojo-template-c.ftlh
+++ b/build-utils/language-c/src/main/resources/templates/c/pojo-template-c.ftlh
@@ -16,7 +16,32 @@
   specific language governing permissions and limitations
   under the License.
 -->
-<#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(typeName)}.c
+<#-- 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.c.CLanguageTemplateHelper" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+<#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.c
 /*
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -76,158 +101,177 @@ plc4c_return_code plc4c_${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_b
 <#list type.fields as field>
     <#switch field.typeName>
         <#case "array">
-  // Array field (${field.name})
+            <#assign arrayField = field>
+
+  // Array field (${arrayField.name})
             <#-- Only update curPos if the length expression uses it -->
-            <#if field.loopExpression.contains("curPos")>
+            <#if arrayField.loopExpression.contains("curPos")>
   curPos = plc4c_spi_read_get_pos(buf) - startPos;
             </#if>
             <#-- In all other cases do we have to work with a list, that is later converted to an array -->
-  plc4c_list ${field.name};
+  plc4c_list ${arrayField.name};
   {
             <#if helper.isCountArrayField(field)>
     // Count array
-    uint8_t itemCount = ${helper.toParseExpression(field.loopExpression, type.parserArguments)?no_esc};
+    uint8_t itemCount = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
     for(int curItem = 0; curItem < itemCount; curItem++) {
-      <#if !helper.isSimpleTypeReference(field.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
+      <#if !helper.isSimpleTypeReference(arrayField.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
       <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
-                <#if helper.isSimpleTypeReference(field.type)>
-      ${helper.getLanguageTypeNameForTypeReference(field.type)} value = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+                <#if helper.isSimpleTypeReference(arrayField.type)>
+      ${helper.getLanguageTypeNameForTypeReference(arrayField.type)} value = ${helper.getReadBufferReadMethodCall(arrayField.type)};
                 <#else>
       <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
       ${helper.getLanguageTypeNameForField(field)}* value = NULL;
-      plc4c_${helper.getCTypeName(field.type.name)}_parse(buf<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${field.name});
+      plc4c_${helper.getCTypeName(arrayField.type.name)}_parse(buf<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(field, parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${arrayField.name});
                 </#if>
-      plc4c_utils_list_insert_head_value(&${field.name}, &value);
+      plc4c_utils_list_insert_head_value(&${arrayField.name}, &value);
     }
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
             <#elseif helper.isLengthArrayField(field)>
     // Length array
-    uint8_t _${field.name}Length = ${helper.toParseExpression(field.loopExpression, type.parserArguments)?no_esc};
-    uint8_t ${field.name}EndPos = plc4c_spi_read_get_pos(buf) + _${field.name}Length;
-    while(plc4c_spi_read_get_pos(buf) < ${field.name}EndPos) {
-      plc4c_utils_list_insert_head_value(&${field.name}, <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>plc4c_${helper.getCTypeName(field.type.name)}_parse(buf<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${field.name})</#if>);
+    uint8_t _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+    uint8_t ${arrayField.name}EndPos = plc4c_spi_read_get_pos(buf) + _${arrayField.name}Length;
+    while(plc4c_spi_read_get_pos(buf) < ${arrayField.name}EndPos) {
+      plc4c_utils_list_insert_head_value(&${arrayField.name}, <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type)}<#else>plc4c_${helper.getCTypeName(arrayField.type.name)}_parse(buf<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(field, parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${field.name})</#if>);
                 <#-- After parsing, update the current position, but only if it's needed -->
-                <#if field.loopExpression.contains("curPos")>
+                <#if arrayField.loopExpression.contains("curPos")>
       curPos = plc4c_spi_read_get_pos(buf) - startPos;
                 </#if>
     }
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
             <#elseif helper.isTerminatedArrayField(field)>
     // Terminated array
-    while(!((boolean) (${helper.toParseExpression(field.loopExpression, type.parserArguments)?no_esc}))) {
-      plc4c_utils_list_insert_head_value(&${field.name}, <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+    while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}))) {
+      plc4c_utils_list_insert_head_value(&${arrayField.name}, <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type)}<#else>${arrayField.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#s [...]
               <#-- After parsing, update the current position, but only if it's needed -->
-              <#if field.loopExpression.contains("curPos")>
+              <#if arrayField.loopExpression.contains("curPos")>
       curPos = plc4c_spi_read_get_pos(buf) - startPos;
               </#if>
     }
             </#if>
   }
-
             <#break>
         <#case "checksum">
-  // Checksum Field (${field.name})
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForType(field.type)};
+            <#assign checksumField = field>
+            <#assign simpleTypeReference = checksumField.type>
+
+  // Checksum Field (${checksumField.name})
   {
     // Create an array of all the bytes read in this message element so far.
     byte[] checksumRawData = plc4c_spi_read_get_bytes(buf, startPos, plc4c_spi_read_get_pos(buf));
-    ${helper.getLanguageTypeNameForField(field)} _${field.name}Ref = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-    ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field.checksumExpression, type.parserArguments)});
-    if(${field.name} != _${field.name}Ref) {
+    ${helper.getLanguageTypeNameForField(field)} _checksumRef = ${helper.getReadBufferReadMethodCall(checksumField.type)};
+    ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, type.parserArguments)});
+    if(_checksum != _checksumRef) {
       return PARSE_ERROR;
-      // throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_${field.name}Ref & 0xFFFF, ${field.name} & 0xFFFF));
+      // throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_checksumRef & 0xFFFF, _checksum & 0xFFFF));
     }
   }
-
             <#break>
         <#case "const">
-  // Const Field (${field.name})
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-  if(${field.name} != ${helper.getCTypeName(type.name)?upper_case}_${helper.camelCaseToSnakeCase(field.name)?upper_case}) {
+            <#assign constField = field>
+            <#assign simpleTypeReference = constField.type>
+
+  // Const Field (${constField.name})
+  ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.type)};
+  if(${constField.name} != ${helper.getCTypeName(type.name)?upper_case}_${helper.camelCaseToSnakeCase(constField.name)?upper_case}) {
     return PARSE_ERROR;
-    // throw new ParseException("Expected constant value " + ${typeName}.${field.name?upper_case} + " but got " + ${field.name});
+    // throw new ParseException("Expected constant value " + ${type.name}.${constField.name?upper_case} + " but got " + ${constField.name});
   }
-
             <#break>
-        <#case "enum">
-  // Enum field (${field.name})
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type))?no_esc};
-  msg->${helper.camelCaseToSnakeCase(field.name)} = ${field.name};
+        <#case "discriminator">
+            <#assign discriminatorField = field>
+            <#assign simpleTypeReference = discriminatorField.type>
 
+  // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
+  ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = ${helper.getReadBufferReadMethodCall(discriminatorField.type)};
             <#break>
-        <#case "discriminator">
-  // Discriminator Field (${field.name}) (Used as input to a switch field)
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+        <#case "enum">
+            <#assign enumField = field>
 
+  // Enum field (${enumField.name})
+  ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type))};
+  msg->${helper.camelCaseToSnakeCase(enumField.name)} = ${enumField.name};
             <#break>
         <#case "implicit">
-  // Implicit Field (${field.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+            <#assign implicitField = field>
+            <#assign simpleTypeReference = implicitField.type>
 
+  // 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.type)};
             <#break>
         <#case "manualArray">
-             <#-- TODO: Implement -->
+            <#assign manualArrayField = field>
 
+  <#-- TODO: Implement -->
             <#break>
         <#case "manual">
-  // Manual Field (${field.name})
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field.parseExpression, type.parserArguments)});
-  msg->${helper.camelCaseToSnakeCase(field.name)} = ${field.name};
+            <#assign manualField = field>
 
+  // Manual Field (${manualField.name})
+  ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, type.parserArguments)});
+  msg->${helper.camelCaseToSnakeCase(manualField.name)} = ${manualField.name};
         <#break>
         <#case "optional">
-  // Optional Field (${field.name}) (Can be skipped, if a given expression evaluates to false)
-            <#if field.conditionExpression.contains("curPos")>
+            <#assign optionalField = field>
+
+  // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
+            <#if optionalField.conditionExpression.contains("curPos")>
   curPos = plc4c_spi_read_get_pos(buf) - startPos;
             </#if>
-  ${helper.getLanguageTypeNameForField(field)}<#if !helper.isSimpleTypeReference(field.type)>*</#if> ${field.name} = <#if !helper.isSimpleTypeReference(field.type)>NULL<#else>0</#if>;
-  if(${helper.toParseExpression(field.conditionExpression, type.parserArguments)?no_esc}) {
-        <#if helper.isSimpleTypeReference(field.type)>
-    ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+  ${helper.getLanguageTypeNameForField(field)}<#if !helper.isSimpleTypeReference(optionalField.type)>*</#if> ${optionalField.name} = <#if !helper.isSimpleTypeReference(optionalField.type)>NULL<#else>0</#if>;
+  if(${helper.toParseExpression(field, optionalField.conditionExpression, type.parserArguments)}) {
+        <#if helper.isSimpleTypeReference(optionalField.type)>
+    ${optionalField.name} = ${helper.getReadBufferReadMethodCall(optionalField.type)};
         <#else>
-    plc4c_${helper.getCTypeName(field.type.name)}* ${field.name} = NULL;
-    plc4c_${helper.getCTypeName(field.type.name)}_parse(buf<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, &${field.name});
+    plc4c_${helper.getCTypeName(optionalField.type.name)}* ${field.name} = NULL;
+    plc4c_${helper.getCTypeName(optionalField.type.name)}_parse(buf<#if optionalField.params?has_content>, <#list optionalField.params as parserTerm>${helper.toParseExpression(optionalField, parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, &${field.name});
         </#if>
-    msg->${helper.camelCaseToSnakeCase(field.name)} = ${field.name};
+    msg->${helper.camelCaseToSnakeCase(optionalField.name)} = ${optionalField.name};
   }
-
             <#break>
         <#case "padding">
-  // Padding Field (${field.name})
-  bool _${field.name}NeedsPadding = (bool) ((plc4c_spi_read_has_more(buf, ${helper.getNumBits(field.type)})) && (${helper.toParseExpression(field.paddingCondition, type.parserArguments)?no_esc}));
-  if(_${field.name}NeedsPadding) {
+            <#assign paddingField = field>
+            <#assign simpleTypeReference = paddingField.type>
+
+  // Padding Field (${paddingField.name})
+  bool _${paddingField.name}NeedsPadding = (bool) ((plc4c_spi_read_has_more(buf, ${helper.getNumBits(paddingField.type)})) && (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)}));
+  if(_${paddingField.name}NeedsPadding) {
     // Just read the padding data and ignore it
-    ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+    ${helper.getReadBufferReadMethodCall(paddingField.type)};
   }
-
             <#break>
         <#case "reserved">
+            <#assign reservedField = field>
+            <#assign simpleTypeReference = reservedField.type>
+
   // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
   {
-    ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-    if(reserved != ${helper.getReservedValue(field)}) {
-      printf("Expected constant value '%d' but got '%d' for reserved field.", ${field.referenceValue}, reserved);
+    ${helper.getLanguageTypeNameForField(field)} _reserved = ${helper.getReadBufferReadMethodCall(reservedField.type)};
+    if(_reserved != ${reservedField.referenceValue}) {
+      printf("Expected constant value '%d' but got '%d' for reserved field.", ${reservedField.referenceValue}, _reserved);
     }
   }
-
             <#break>
         <#case "simple">
-  // Simple Field (${field.name})
+            <#assign simpleField = field>
+
+  // Simple Field (${simpleField.name})
             <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
-            <#if helper.isSimpleTypeReference(field.type)>
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+            <#if helper.isSimpleTypeReference(simpleField.type)>
+  ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = ${helper.getReadBufferReadMethodCall(simpleField.type)};
             <#else>
             <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
-  ${helper.getLanguageTypeNameForField(field)}* ${field.name} = NULL;
-  plc4c_${helper.getCTypeName(field.type.name)}_parse(buf<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${field.name});
+  ${helper.getLanguageTypeNameForField(field)}* ${simpleField.name} = NULL;
+  plc4c_${helper.getCTypeName(simpleField.type.name)}_parse(buf<#if simpleField.params?has_content>, <#list simpleField.params as parserTerm>${helper.toParseExpression(simpleField, parserTerm, type.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${simpleField.name});
             </#if>
-  msg->${helper.camelCaseToSnakeCase(field.name)} = ${field.name};
-
+  msg->${helper.camelCaseToSnakeCase(simpleField.name)} = ${simpleField.name};
             <#break>
         <#case "switch">
+            <#assign switchField = field>
+
   // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
-            <#list field.cases as case>
-  <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if>${helper.toVariableParseExpression(field.discriminatorExpressions[discriminatorValue?index], type.parserArguments)?no_esc}<#--${helper.toVariableParseExpressionHurz(field)}--> == ${discriminatorValue}<#if case.discriminatorValues?size &gt; 1>)</#if><#sep> && </#sep></#list>) </#if>{ /* ${case.name} */
+            <#list switchField.cases as case>
+  <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if>${helper.toVariableParseExpression(switchField, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == ${discriminatorValue}<#if case.discriminatorValues?size &gt; 1>)</#if><#sep> && </#sep></#list>) </#if>{ /* ${case.name} */
                 <#list case.propertyFields as caseField>
     ${helper.getLanguageTypeNameForField(caseField)}<#if !helper.isSimpleTypeReference(caseField.type)>*</#if> ${caseField.name}<#if field.loopType??>${helper.getLoopExpressionSuffix(caseField)}</#if><#if helper.getLanguageTypeNameForField(caseField) == "plc4c_list"><#elseif !helper.isSimpleTypeReference(caseField.type)> = NULL<#else> = -1</#if>;
     msg->${helper.camelCaseToSnakeCase(case.name)}_${helper.camelCaseToSnakeCase(caseField.name)} = ${caseField.name};
@@ -236,12 +280,12 @@ plc4c_return_code plc4c_${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_b
                 </#list>
   }<#sep> else </#sep>
             </#list>
-
             <#break>
         <#case "virtual">
-  // Virtual field (Just declare a local variable so we can access it in the parser)
-  ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field.valueExpression, type.parserArguments)});
+            <#assign virtualField = field>
 
+  // Virtual field (Just declare a local variable so we can access it in the parser)
+  ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)});
             <#break>
     </#switch>
 </#list>
@@ -252,4 +296,5 @@ plc4c_return_code plc4c_${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_b
 plc4c_return_code plc4c_${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* buf, plc4c_${helper.getCTypeName(type.name)}* message) {
   return OK;
 }
-</#if>
\ No newline at end of file
+</#if>
+</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-c/src/main/resources/templates/c/pojo-template-h.ftlh b/build-utils/language-c/src/main/resources/templates/c/pojo-template-h.ftlh
index b3599ff..3acf661 100644
--- a/build-utils/language-c/src/main/resources/templates/c/pojo-template-h.ftlh
+++ b/build-utils/language-c/src/main/resources/templates/c/pojo-template-h.ftlh
@@ -16,7 +16,32 @@
   specific language governing permissions and limitations
   under the License.
 -->
-<#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(typeName)}.h
+<#-- 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.c.CLanguageTemplateHelper" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+<#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.h
 /*
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -49,7 +74,7 @@ extern "C" {
 -->
 <#if helper.getComplexTypeReferences()?has_content>
     <#list helper.getComplexTypeReferences() as typeReference>
-#include "${helper.camelCaseToSnakeCase(typeReference.name)}.h"
+#include "${helper.camelCaseToSnakeCase(typeReference)}.h"
     </#list>
 </#if>
 <#--
@@ -136,4 +161,5 @@ plc4c_return_code plc4c_${helper.getCTypeName(type.name)}_serialize(plc4c_spi_wr
 }
 #endif
 #endif  // PLC4C_${helper.getCTypeName(type.name)?upper_case}_H_
-</#if>
\ No newline at end of file
+</#if>
+</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index fe235bc..5a3d58b 100644
--- a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -21,7 +21,7 @@ package org.apache.plc4x.language.java;
 
 import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.commons.text.WordUtils;
-import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
 import org.apache.plc4x.plugins.codegenerator.types.fields.*;
 import org.apache.plc4x.plugins.codegenerator.types.references.*;
@@ -29,22 +29,12 @@ import org.apache.plc4x.plugins.codegenerator.types.terms.*;
 
 import java.util.*;
 import java.util.function.Function;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 @SuppressWarnings({"unused", "WeakerAccess"})
-public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHelper {
-
-    private final TypeDefinition thisType;
-    private final String protocolName;
-    private final String flavorName;
-    private final Map<String, TypeDefinition> types;
+public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
 
     public JavaLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
-        this.thisType = thisType;
-        this.protocolName = protocolName;
-        this.flavorName = flavorName;
-        this.types = types;
+        super(thisType, protocolName, flavorName, types);
     }
 
     public String packageName(String protocolName, String languageName, String languageFlavorName) {
@@ -53,36 +43,37 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             String.join("", languageFlavorName.split("\\-"));
     }
 
-    public String getLanguageTypeNameForField(TypedField field) {
+    @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();
-                final TypeDefinition typeDefinition = types.get(complexTypeReference.getName());
+                final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
                 if(typeDefinition instanceof DataIoTypeDefinition) {
                     return "PlcValue";
                 }
             }
         }
-        return getLanguageTypeNameForField(field, !optional);
+        return getLanguageTypeNameForTypeReference(((TypedField) field).getType(), !optional);
     }
 
     public String getNonPrimitiveLanguageTypeNameForField(TypedField field) {
-        return getLanguageTypeNameForField(field, false);
+        return getLanguageTypeNameForTypeReference(field.getType(), false);
     }
 
-    private String getLanguageTypeNameForField(TypedField field, boolean allowPrimitive) {
-        TypeReference typeReference = field.getType();
-        return getLanguageTypeName(typeReference, allowPrimitive);
+    public String getLanguageTypeNameForSpecType(TypeReference typeReference) {
+        return getLanguageTypeNameForTypeReference(typeReference, true);
     }
 
-    public String getLanguageTypeNameForSpecType(TypeReference typeReference) {
-        return getLanguageTypeName(typeReference, true);
+    @Override
+    public String getLanguageTypeNameForTypeReference(TypeReference typeReference) {
+        return getLanguageTypeNameForTypeReference(typeReference, false);
     }
 
-    public String getLanguageTypeName(TypeReference typeReference, boolean allowPrimitive) {
+    public String getLanguageTypeNameForTypeReference(TypeReference typeReference, boolean allowPrimitive) {
         if(typeReference instanceof SimpleTypeReference) {
             SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
             switch (simpleTypeReference.getBaseType()) {
@@ -147,13 +138,14 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                     return "LocalDateTime";
                 }
             }
-            return "Hurz";
+            throw new RuntimeException("Unsupported simple type");
         } else {
             return ((ComplexTypeReference) typeReference).getName();
         }
     }
 
-    public String getNullValueForType(TypeReference typeReference) {
+    @Override
+    public String getNullValueForTypeReference(TypeReference typeReference) {
         if(typeReference instanceof SimpleTypeReference) {
             SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
             switch (simpleTypeReference.getBaseType()) {
@@ -202,20 +194,20 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         }
     }
 
-    public String getArgumentType(TypeReference typeReference, int index) {
+    /*public String getArgumentType(TypeReference typeReference, int index) {
         if(typeReference instanceof ComplexTypeReference) {
             ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
-            if(!types.containsKey(complexTypeReference.getName())) {
+            if(!getTypeDefinitions().containsKey(complexTypeReference.getName())) {
                 throw new RuntimeException("Could not find definition of complex type " + complexTypeReference.getName());
             }
-            TypeDefinition complexTypeDefinition = types.get(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()) {
@@ -300,6 +292,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         return "Hurz";
     }
 
+    @Override
     public String getWriteBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String fieldName) {
         switch (simpleTypeReference.getBaseType()) {
             case BIT: {
@@ -360,7 +353,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         return "Hurz";
     }
 
-    public String getReadMethodName(SimpleTypeReference simpleTypeReference) {
+    /*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)) {
@@ -368,10 +361,10 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         } else {
             return "read" + languageTypeName;
         }
-    }
+    }*/
 
     public String getReservedValue(ReservedField reservedField) {
-        final String languageTypeName = getLanguageTypeName(reservedField.getType(), true);
+        final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType(), true);
         if("BigInteger".equals(languageTypeName)) {
             return "BigInteger.valueOf(" + reservedField.getReferenceValue() + ")";
         } else {
@@ -379,7 +372,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         }
     }
 
-    public Collection<ComplexTypeReference> getComplexTypes(ComplexTypeDefinition complexTypeDefinition) {
+    /*public Collection<ComplexTypeReference> getComplexTypes(ComplexTypeDefinition complexTypeDefinition) {
         Map<String, ComplexTypeReference> types = new HashMap<>();
         for (Field field : complexTypeDefinition.getFields()) {
             if(field instanceof TypedField) {
@@ -401,9 +394,9 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             }
         }
         return types.values();
-    }
+    }*/
 
-    public Collection<ComplexTypeReference> getEnumTypes(ComplexTypeDefinition complexTypeDefinition) {
+    /*public Collection<ComplexTypeReference> getEnumTypes(ComplexTypeDefinition complexTypeDefinition) {
         Map<String, ComplexTypeReference> types = new HashMap<>();
         for (Field field : complexTypeDefinition.getFields()) {
             if(field instanceof EnumField) {
@@ -424,83 +417,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             }
         }
         return types.values();
-    }
-
-    public boolean isSimpleType(TypeReference typeReference) {
-        return typeReference instanceof SimpleTypeReference;
-    }
-
-    public boolean isDiscriminatedType(TypeDefinition typeDefinition) {
-        return typeDefinition instanceof DiscriminatedComplexTypeDefinition;
-    }
-
-    public String getDiscriminatorConstantType(DiscriminatedComplexTypeDefinition type, int index) {
-        final ComplexTypeDefinition parentType = (ComplexTypeDefinition) type.getParentType();
-        final Optional<Field> typeSwitchField = parentType.getFields().stream().filter(field -> field instanceof SwitchField).findFirst();
-        final SwitchField switchField = (SwitchField) typeSwitchField.get();
-        /*erm discriminatorExpression = switchField.getDiscriminatorExpressions()[index];
-        final Optional<Field> regularField = parentType.getFields().stream().filter(field ->
-            ((field instanceof PropertyField) && ((PropertyField) field).getName().equals(fieldName)) ||
-                ((field instanceof ImplicitField) && ((ImplicitField) field).getName().equals(fieldName)) ||
-                ((field instanceof DiscriminatorField) && ((DiscriminatorField) field).getName().equals(fieldName))).findFirst();
-        if(regularField.isPresent()) {
-            final Field field = regularField.get();
-            if(field instanceof PropertyField) {
-                return getLanguageTypeName(((PropertyField) field).getType(), true);
-            } else if(field instanceof ImplicitField) {
-                return getLanguageTypeName(((ImplicitField) field).getType(), true);
-            } else {
-                return getLanguageTypeName(((DiscriminatorField) field).getType(), true);
-            }
-        }
-        final Optional<Argument> typeArgument = Arrays.stream(type.getParserArguments()).filter(argument -> fieldName.equals(argument.getName())).findFirst();
-        if(typeArgument.isPresent()) {
-            return getLanguageTypeName(typeArgument.get().getType(), true);
-        }*/
-        return "Object";
-    }
-
-    public boolean isAbstractField(Field field) {
-        return field instanceof AbstractField;
-    }
-
-    public boolean isCountArray(ArrayField arrayField) {
-        return arrayField.getLoopType() == ArrayField.LoopType.COUNT;
-    }
-
-    public boolean isLengthArray(ArrayField arrayField) {
-        return arrayField.getLoopType() == ArrayField.LoopType.LENGTH;
-    }
-
-    public boolean isTerminatedArray(ArrayField arrayField) {
-        return arrayField.getLoopType() == ArrayField.LoopType.TERMINATED;
-    }
-
-    public boolean isCountArray(ManualArrayField arrayField) {
-        return arrayField.getLoopType() == ManualArrayField.LoopType.COUNT;
-    }
-
-    public boolean isLengthArray(ManualArrayField arrayField) {
-        return arrayField.getLoopType() == ManualArrayField.LoopType.LENGTH;
-    }
-
-    public boolean isTerminatedArray(ManualArrayField arrayField) {
-        return arrayField.getLoopType() == ManualArrayField.LoopType.TERMINATED;
-    }
-
-    public String toSwitchExpression(String expression) {
-        StringBuilder sb = new StringBuilder();
-        Pattern pattern = Pattern.compile("([^\\.]*)\\.([a-zA-Z\\d]+)(.*)");
-        Matcher matcher;
-        while ((matcher = pattern.matcher(expression)).matches()) {
-            String prefix = matcher.group(1);
-            String middle = matcher.group(2);
-            sb.append(prefix).append(".get").append(WordUtils.capitalize(middle)).append("()");
-            expression = matcher.group(3);
-        }
-        sb.append(expression);
-        return sb.toString();
-    }
+    }*/
 
     public String toParseExpression(TypedField field, Term term, Argument[] parserArguments) {
         return toExpression(field, term, term1 -> toVariableParseExpression(field, term1, parserArguments));
@@ -526,7 +443,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             } else if(term instanceof VariableLiteral) {
                 VariableLiteral variableLiteral = (VariableLiteral) term;
                 // If this literal references an Enum type, then we have to output it differently.
-                if(types.get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
+                if(getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
                     return variableLiteral.getName() + "." + variableLiteral.getChild().getName();
                 } else {
                     return variableExpressionGenerator.apply(term);
@@ -722,26 +639,6 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             sb.append(")");
             return sb.toString();
         }
-        // Discriminator values have to be handled a little differently.
-        else if(vl.getName().equals("DISCRIMINATOR_VALUES")) {
-            final String typeName = getLanguageTypeNameForSpecType(field.getType());
-            switch (typeName) {
-                case "byte":
-                    return "((Number) _value.getDiscriminatorValues()[" + vl.getIndex() + "]).byteValue()";
-                case "short":
-                    return "((Number) _value.getDiscriminatorValues()[" + vl.getIndex() + "]).shortValue()";
-                case "int":
-                    return "((Number) _value.getDiscriminatorValues()[" + vl.getIndex() + "]).intValue()";
-                case "long":
-                    return "((Number) _value.getDiscriminatorValues()[" + vl.getIndex() + "]).longValue()";
-                case "float":
-                    return "((Number) _value.getDiscriminatorValues()[" + vl.getIndex() + "]).floatValue()";
-                case "double":
-                    return "((Number) _value.getDiscriminatorValues()[" + vl.getIndex() + "]).doubleValue()";
-                default:
-                    return "_value.getDiscriminatorValues()[" + vl.getIndex() + "]";
-            }
-        }
         // All uppercase names are not fields, but utility methods.
         else if(vl.getName().equals(vl.getName().toUpperCase())) {
             StringBuilder sb = new StringBuilder(vl.getName());
@@ -890,15 +787,6 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         return valueString;
     }
 
-    public SimpleTypeReference getEnumBaseType(TypeReference enumType) {
-        if(!(enumType instanceof ComplexTypeReference)) {
-            throw new RuntimeException("type reference for enum types must be of type complex type");
-        }
-        ComplexTypeReference complexType = (ComplexTypeReference) enumType;
-        EnumTypeDefinition enumTypeDefinition = (EnumTypeDefinition) types.get(complexType.getName());
-        return (SimpleTypeReference) enumTypeDefinition.getType();
-    }
-
     public List<Argument> getSerializerArguments(Argument[] arguments) {
         List<Argument> serializerArguments = new LinkedList<>();
         if(arguments != null) {
diff --git a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
index 8591e2c..7148dee 100644
--- a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
@@ -16,7 +16,32 @@
   specific language governing permissions and limitations
   under the License.
 -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${typeName}IO.java
+<#-- 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="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+${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
@@ -58,12 +83,12 @@ import java.time.*;
 import java.util.*;
 import java.util.function.Supplier;
 
-public class ${typeName}IO {
+public class ${type.name}IO {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(${typeName}IO.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
 
-    public static PlcValue staticParse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
-        <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(type.switchField.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
+    public static PlcValue staticParse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+        <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
             <#assign skipReturn=false>
             <#list case.fields as field>
                 <#switch field.typeName>
@@ -75,40 +100,40 @@ public class ${typeName}IO {
             curPos = io.getPos() - startPos;
                         </#if>
             <#-- If this is a count array, we can directly initialize an array with the given size -->
-                        <#if helper.isCountArray(field)>
+                        <#if helper.isCountArrayField(field)>
             // Count array
-            if(${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc} > Integer.MAX_VALUE) {
-                throw new ParseException("Array count of " + (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+            if(${helper.toParseExpression(field, field.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) {
+                throw new ParseException("Array count of " + (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
             }
             ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[] ${field.name};
             {
-                int itemCount = (int) ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc};
+                int itemCount = (int) ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
                 ${field.name} = new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[itemCount];
                 for(int curItem = 0; curItem < itemCount; curItem++) {
-                    ${field.name}[curItem] = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>;
+                    ${field.name}[curItem] = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
                 }
             }
             <#-- In all other cases do we have to work with a list, that is later converted to an array -->
                         <#else>
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-                            <#if helper.isLengthArray(field)>
+                            <#if helper.isLengthArrayField(field)>
             // Length array
-            int _${field.name}Length = ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc};
+            int _${field.name}Length = ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
             List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
             int ${field.name}EndPos = io.getPos() + _${field.name}Length;
             while(io.getPos() < ${field.name}EndPos) {
-                _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+                _${field.name}List.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>);
                 <#-- After parsing, update the current position, but only if it's needed -->
                                 <#if field.loopExpression.contains("curPos")>
                 curPos = io.getPos() - startPos;
                                 </#if>
             }
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-                            <#elseif helper.isTerminatedArray(field)>
+                            <#elseif helper.isTerminatedArrayField(field)>
             // Terminated array
             List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-            while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc}))) {
-                _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+            while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)}))) {
+                _${field.name}List.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>);
 
                 <#-- After parsing, update the current position, but only if it's needed -->
                                 <#if field.loopExpression.contains("curPos")>
@@ -121,7 +146,7 @@ public class ${typeName}IO {
                 type we have to iterate over it's elements and explicitly cast them.
                 Otherwise a simple toArray call is fine.
             -->
-                            <#if helper.isSimpleType(field.type)>
+                            <#if helper.isSimpleTypeReference(field.type)>
             ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[_${field.name}List.size()];
             for(int i = 0; i < _${field.name}List.size(); i++) {
                 ${field.name}[i] = (${helper.getNonPrimitiveLanguageTypeNameForField(field)}) _${field.name}List.get(i);
@@ -134,20 +159,20 @@ public class ${typeName}IO {
                     <#case "const">
 
             // Const Field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-            if(${field.name} != ${typeName}.${field.name?upper_case}) {
-                throw new ParseException("Expected constant value " + ${typeName}.${field.name?upper_case} + " but got " + ${field.name});
+            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)};
+            if(${field.name} != ${type.name}.${field.name?upper_case}) {
+                throw new ParseException("Expected constant value " + ${type.name}.${field.name?upper_case} + " but got " + ${field.name});
             }
                     <#break>
                     <#case "enum">
 
             // Enum field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(field)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseType(field.type))?no_esc});
+            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(field)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type))});
                     <#break>
                     <#case "manual">
 
             // Manual Field (${field.name})
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)?no_esc});
+            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)});
                         <#-- If a manual field is detected, the value returned by this is instantly treated as the value -->
                         <#switch case.name>
                             <#case "Time">
@@ -175,7 +200,7 @@ public class ${typeName}IO {
 
             // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
             {
-                ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+                ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(field.type)};
                 if(reserved != ${helper.getReservedValue(field)}) {
                     LOGGER.info("Expected constant value " + ${field.referenceValue} + " but got " + reserved + " for reserved field.");
                 }
@@ -184,7 +209,7 @@ public class ${typeName}IO {
                     <#case "simple">
 
             // Simple Field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep [...]
                     <#break>
                 </#switch>
             </#list>
@@ -224,8 +249,8 @@ public class ${typeName}IO {
     }
 
 <#if outputFlavor != "passive">
-    public static WriteBuffer staticSerialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
-        <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(type.switchField.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
+    public static WriteBuffer staticSerialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+        <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
             WriteBuffer io = new WriteBuffer(${helper.getSizeInBits(case, type.parserArguments)} / 8 );
             <#list case.fields as field>
                 <#switch field.typeName>
@@ -233,20 +258,20 @@ public class ${typeName}IO {
                     <#break>
                     <#case "const">
             // Const Field (${field.name})
-            ${helper.getWriteBufferReadMethodCall(field.type, field.referenceValue)?no_esc};
+            ${helper.getWriteBufferReadMethodCall(field.type, field.referenceValue)};
                     <#break>
                     <#case "enum">
             // Enum field (${field.name})
             ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${field.name?cap_first}();
-            ${helper.getWriteBufferReadMethodCall(helper.getEnumBaseType(field.type), "(" + field.name + ".getValue())")?no_esc};
+            ${helper.getWriteBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type), "(" + field.name + ".getValue())")};
                     <#break>
                     <#case "manual">
             // Manual Field (${field.name})
-            ${helper.toSerializationExpression(field, field.serializeExpression, type.parserArguments)?no_esc};
+            ${helper.toSerializationExpression(field, field.serializeExpression, type.parserArguments)};
                     <#break>
                     <#case "reserved">
             // Reserved Field
-            ${helper.getWriteBufferReadMethodCall(field.type, helper.getReservedValue(field))?no_esc};
+            ${helper.getWriteBufferReadMethodCall(field.type, helper.getReservedValue(field))};
                     <#break>
                     <#case "simple">
             // Simple Field (${field.name})
@@ -257,11 +282,11 @@ public class ${typeName}IO {
             ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${case.name}();
                             <#else>
                                 <#-- Just for now -->
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForType(field.type)};
+            ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForTypeReference(field.type)};
                             </#if>
                         </#if>
-                        <#if helper.isSimpleType(field.type)>
-            ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
+                        <#if helper.isSimpleTypeReference(field.type)>
+            ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")};
                         <#else>
             ${field.type.name}IO.staticSerialize(io, ${field.name});
                         </#if>
@@ -274,4 +299,5 @@ public class ${typeName}IO {
     }
 </#if>
 
-}
\ No newline at end of file
+}
+</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-java/src/main/resources/templates/java/enum-package-info-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/enum-package-info-template.ftlh
index 27bf875..a944e9c 100644
--- a/build-utils/language-java/src/main/resources/templates/java/enum-package-info-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/enum-package-info-template.ftlh
@@ -16,6 +16,13 @@
   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" -->
 ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/types/package-info.java
 /*
   Licensed to the Apache Software Foundation (ASF) under one
@@ -37,3 +44,4 @@ ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")
 */
 
 package ${helper.packageName(protocolName, languageName, outputFlavor)}.types;
+</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-java/src/main/resources/templates/java/enum-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/enum-template.ftlh
index 8ab5ce2..e428a40 100644
--- a/build-utils/language-java/src/main/resources/templates/java/enum-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/enum-template.ftlh
@@ -17,7 +17,15 @@
   specific language governing permissions and limitations
   under the License.
 -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/types/${typeName}.java
+<#-- 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="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/types/${type.name}.java
 /*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -46,30 +54,30 @@ import org.slf4j.LoggerFactory;
 import java.util.HashMap;
 import java.util.Map;
 
-public enum ${typeName} {
+public enum ${type.name} {
 
 <#list type.enumValues as enumValue>
-${enumValue.name}((${helper.getLanguageTypeName(type.type, true)}) ${enumValue.value}<#if type.constantNames?has_content>, <#list type.constantNames as constantName>(${helper.getLanguageTypeName(type.getConstantType(constantName), true)}) ${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName))?no_esc}<#sep>, </#sep></#list></#if>)<#sep>,
+${enumValue.name}((${helper.getLanguageTypeNameForTypeReference(type.type, true)}) ${enumValue.value}<#if type.constantNames?has_content>, <#list type.constantNames as constantName>(${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)}) ${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName))}<#sep>, </#sep></#list></#if>)<#sep>,
 </#sep></#list>;
 
-private static final Logger logger = LoggerFactory.getLogger(${typeName}.class);
+private static final Logger logger = LoggerFactory.getLogger(${type.name}.class);
 
-private static final Map<${helper.getLanguageTypeName(type.type, false)}, ${typeName}> map;
+private static final Map<${helper.getLanguageTypeNameForTypeReference(type.type, false)}, ${type.name}> map;
 static {
 map = new HashMap<>();
-for (${typeName} value : ${typeName}.values()) {
-map.put((${helper.getLanguageTypeName(type.type, true)}) value.getValue(), value);
+for (${type.name} value : ${type.name}.values()) {
+map.put((${helper.getLanguageTypeNameForTypeReference(type.type, true)}) value.getValue(), value);
 }
 }
 
-private ${helper.getLanguageTypeName(type.type, true)} value;
+private ${helper.getLanguageTypeNameForTypeReference(type.type, true)} value;
 <#if type.constantNames?has_content>
     <#list type.constantNames as constantName>
-        private ${helper.getLanguageTypeName(type.getConstantType(constantName), true)} ${constantName};
+        private ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} ${constantName};
     </#list>
 </#if>
 
-${typeName}(${helper.getLanguageTypeName(type.type, true)} value<#if type.constantNames?has_content>, <#list type.constantNames as constantName>${helper.getLanguageTypeName(type.getConstantType(constantName), true)} ${constantName}<#sep>, </#sep></#list></#if>) {
+${type.name}(${helper.getLanguageTypeNameForTypeReference(type.type, true)} value<#if type.constantNames?has_content>, <#list type.constantNames as constantName>${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} ${constantName}<#sep>, </#sep></#list></#if>) {
 this.value = value;
 <#if type.constantNames?has_content>
     <#list type.constantNames as constantName>
@@ -78,23 +86,24 @@ this.value = value;
 </#if>
 }
 
-public ${helper.getLanguageTypeName(type.type, true)} getValue() {
+public ${helper.getLanguageTypeNameForTypeReference(type.type, true)} getValue() {
 return value;
 }
 
 <#if type.constantNames?has_content>
     <#list type.constantNames as constantName>
-        public ${helper.getLanguageTypeName(type.getConstantType(constantName), true)} get${constantName?cap_first}() {
+        public ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} get${constantName?cap_first}() {
         return ${constantName};
         }
 
     </#list>
 </#if>
-public static ${typeName} valueOf(${helper.getLanguageTypeName(type.type, true)} value) {
+public static ${type.name} valueOf(${helper.getLanguageTypeNameForTypeReference(type.type, true)} value) {
 if (!map.containsKey(value)) {
-logger.error("No ${typeName} for value {}", value);
+logger.error("No ${type.name} for value {}", value);
 }
 return map.get(value);
 }
 
-}
\ No newline at end of file
+}
+</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
index 6087f98..9fc2a4d 100644
--- a/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/io-template.ftlh
@@ -16,7 +16,33 @@
   specific language governing permissions and limitations
   under the License.
 -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${typeName}IO.java
+<#-- 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="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="typedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.TypedField" -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+${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
@@ -41,7 +67,7 @@ package ${helper.packageName(protocolName, languageName, outputFlavor)}.io;
 import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
 
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
-<#if helper.getComplexTypes(type)?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if>
+<#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.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.spi.generation.*;
@@ -56,110 +82,114 @@ import java.time.*;
 import java.util.*;
 import java.util.function.Supplier;
 
-public class ${typeName}IO implements <#if outputFlavor != "passive">MessageIO<${typeName}, ${typeName}><#else>MessageInput<${typeName}></#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(${typeName}IO.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
 
-<#if !helper.isDiscriminatedType(type)>
+<#-- The parse and serialize methods here are just proxies for forwardning the requests to static counterparts -->
+<#if !helper.isDiscriminatedChildTypeDefinition()>
     @Override
-    public ${typeName} parse(ReadBuffer io, Object... args) throws ParseException {
+    public ${type.name} parse(ReadBuffer io, Object... args) throws ParseException {
         <#if type.parserArguments?has_content>
         if((args == null) || (args.length != ${type.parserArguments?size})) {
             throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length);
         }
         <#list type.parserArguments as parserArgument>
-        if(!(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeName(parserArgument.type, false)})) {
-            throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeName(parserArgument.type, false)} but was " + args[${parserArgument?index}].getClass().getName());
+        if(!(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)})) {
+            throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} but was " + args[${parserArgument?index}].getClass().getName());
         }
-        ${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name} = (${helper.getLanguageTypeName(parserArgument.type, false)}) args[${parserArgument?index}];
+        ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name} = (${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) args[${parserArgument?index}];
         </#list>
         </#if>
-        return ${typeName}IO.staticParse(io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+        return ${type.name}IO.staticParse(io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
     }
 
     <#if outputFlavor != "passive">
     @Override
-    public void serialize(WriteBuffer io, ${typeName} value, Object... args) throws ParseException {
+    public void serialize(WriteBuffer io, ${type.name} value, Object... args) throws ParseException {
         <#if helper.getSerializerArguments(type.parserArguments)?has_content>
         if((args == null) || (args.length != ${type.parserArguments?size})) {
             throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length);
         }
         <#list helper.getSerializerArguments(type.parserArguments) as serializerArgument>
-        if(!(args[${serializerArgument?index}] instanceof ${helper.getLanguageTypeName(serializerArgument.type, false)})) {
-            throw new PlcRuntimeException("Argument ${serializerArgument?index} expected to be of type ${helper.getLanguageTypeName(serializerArgument.type, false)} but was " + args[${serializerArgument?index}].getClass().getName());
+        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.getLanguageTypeName(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeName(serializerArgument.type, false)}) args[${serializerArgument?index}];
+        ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)}) args[${serializerArgument?index}];
         </#list>
         </#if>
-        ${typeName}IO.staticSerialize(io, value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+        ${type.name}IO.staticSerialize(io, value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
     }
 
     </#if>
 <#else>
     @Override
-    public ${typeName} parse(ReadBuffer io, Object... args) throws ParseException {
-        return (${typeName}) new ${type.parentType.name}IO().parse(io, args);
+    public ${type.name} parse(ReadBuffer io, Object... args) throws ParseException {
+        return (${type.name}) new ${type.parentType.name}IO().parse(io, args);
     }
 
 <#if outputFlavor != "passive">
     @Override
-    public void serialize(WriteBuffer io, ${typeName} value, Object... args) throws ParseException {
+    public void serialize(WriteBuffer io, ${type.name} value, Object... args) throws ParseException {
         new ${type.parentType.name}IO().serialize(io, value, args);
     }
 
 </#if>
 </#if>
-    public static ${typeName}<#if helper.isDiscriminatedType(type)>Builder</#if> staticParse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+<#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing -->
+    public static ${type.name}<#if helper.isDiscriminatedChildTypeDefinition()>Builder</#if> staticParse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         int startPos = io.getPos();
         int curPos;
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
+        <#assign arrayField = field>
 
-        // Array field (${field.name})
+        // Array field (${arrayField.name})
         <#-- Only update curPos if the length expression uses it -->
-        <#if field.loopExpression.contains("curPos")>
+        <#if arrayField.loopExpression.contains("curPos")>
         curPos = io.getPos() - startPos;
         </#if>
         <#-- If this is a count array, we can directly initialize an array with the given size -->
-        <#if helper.isCountArray(field)>
+        <#if helper.isCountArrayField(field)>
         // Count array
-        if(${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc} > Integer.MAX_VALUE) {
-            throw new ParseException("Array count of " + (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+        if(${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) {
+            throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
         }
-        ${helper.getLanguageTypeNameForField( field)}[] ${field.name};
+        ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name};
         {
-            int itemCount = (int) ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc};
-            ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
+            int itemCount = (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+            ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
             for(int curItem = 0; curItem < itemCount; curItem++) {
-                <#if !helper.isSimpleType(field.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
-                ${field.name}[curItem] = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>;
+                <#-- When parsing simple types, there is nothing that could require the "lastItem" -->
+                <#if !helper.isSimpleTypeReference(arrayField.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
+                ${arrayField.name}[curItem] = <#if helper.isSimpleTypeReference(arrayField.type)><#assign simpleTypeReference = arrayField.type>${helper.getReadBufferReadMethodCall(simpleTypeReference)}<#else>${arrayField.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument,  [...]
             }
         }
         <#-- In all other cases do we have to work with a list, that is later converted to an array -->
         <#else>
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-            <#if helper.isLengthArray(field)>
+            <#if helper.isLengthArrayField(field)>
         // Length array
-        int _${field.name}Length = ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc};
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        int ${field.name}EndPos = io.getPos() + _${field.name}Length;
-        while(io.getPos() < ${field.name}EndPos) {
-            _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+        int _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
+        int ${arrayField.name}EndPos = io.getPos() + _${arrayField.name}Length;
+        while(io.getPos() < ${arrayField.name}EndPos) {
+            _${arrayField.name}List.add(<#if helper.isSimpleTypeReference(arrayField.type)><#assign simpleTypeReference = arrayField.type>${helper.getReadBufferReadMethodCall(simpleTypeReference)}<#else>${arrayField.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.p [...]
             <#-- After parsing, update the current position, but only if it's needed -->
-            <#if field.loopExpression.contains("curPos")>
+            <#if arrayField.loopExpression.contains("curPos")>
             curPos = io.getPos() - startPos;
             </#if>
         }
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-            <#elseif helper.isTerminatedArray(field)>
+            <#elseif helper.isTerminatedArrayField(field)>
         // Terminated array
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)?no_esc}))) {
-            _${field.name}List.add(<#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)?no_esc})<#sep>, </#sep></#list></#if>)</#if>);
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
+        while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}))) {
+            _${arrayField.name}List.add(<#if helper.isSimpleTypeReference(arrayField.type)><#assign simpleTypeReference = arrayField.type>${helper.getReadBufferReadMethodCall(simpleTypeReference)}<#else>${arrayField.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.p [...]
 
             <#-- After parsing, update the current position, but only if it's needed -->
-            <#if field.loopExpression.contains("curPos")>
+            <#if arrayField.loopExpression.contains("curPos")>
             curPos = io.getPos() - startPos;
             </#if>
         }
@@ -169,92 +199,102 @@ public class ${typeName}IO implements <#if outputFlavor != "passive">MessageIO<$
                 type we have to iterate over it's elements and explicitly cast them.
                 Otherwise a simple toArray call is fine.
             -->
-            <#if helper.isSimpleType(field.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}List.size()];
-        for(int i = 0; i < _${field.name}List.size(); i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${field.name}List.get(i);
+            <#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)}[] ${field.name} = _${field.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[0]);
+        ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]);
             </#if>
         </#if>
         <#break>
     <#case "checksum">
+        <#assign checksumField = field>
+        <#assign simpleTypeReference = checksumField.type>
 
-        // Checksum Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForType(field.type)};
+        // Checksum Field (checksum)
         {
+            ${helper.getLanguageTypeNameForField(field)} checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
             // Create an array of all the bytes read in this message element so far.
             byte[] checksumRawData = io.getBytes(startPos, io.getPos());
-            ${helper.getLanguageTypeNameForField(field)} _${field.name}Ref = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-            ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.checksumExpression, type.parserArguments)});
-            if(${field.name} != _${field.name}Ref) {
-                throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_${field.name}Ref & 0xFFFF, ${field.name} & 0xFFFF));
+            ${helper.getLanguageTypeNameForField(field)} checksumRef = ${helper.getReadBufferReadMethodCall(simpleTypeReference)};
+            checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, type.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>
+        <#assign simpleTypeReference = constField.type>
 
-        // Const Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-        if(${field.name} != ${typeName}.${field.name?upper_case}) {
-            throw new ParseException("Expected constant value " + ${typeName}.${field.name?upper_case} + " but got " + ${field.name});
+        // Const Field (${constField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getReadBufferReadMethodCall(simpleTypeReference)};
+        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});
         }
         <#break>
-    <#case "enum">
+    <#case "discriminator">
+        <#assign discriminatorField = field>
+        <#assign simpleTypeReference = discriminatorField.type>
 
-        // Enum field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseType(field.type))?no_esc});
+        // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
+        ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = ${helper.getReadBufferReadMethodCall(simpleTypeReference)};
         <#break>
-    <#case "discriminator">
+    <#case "enum">
+        <#assign enumField = field>
 
-        // Discriminator Field (${field.name}) (Used as input to a switch field)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+        // Enum field (${enumField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type))});
         <#break>
     <#case "implicit">
+        <#assign implicitField = field>
+        <#assign simpleTypeReference = implicitField.type>
 
-        // Implicit Field (${field.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+        // 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(simpleTypeReference)};
         <#break>
     <#case "manualArray">
+        <#assign manualArrayField = field>
 
-        // Manual Array Field (${field.name})
+        // Manual Array Field (${manualArrayField.name})
         <#-- Only update curPos if the length expression uses it -->
-        <#if field.loopExpression.contains("curPos")>
+        <#if manualArrayField.loopExpression.contains("curPos")>
         curPos = io.getPos() - startPos;
         </#if>
         <#-- If this is a count array, we can directly initialize an array with the given size -->
-        <#if helper.isCountArray(field)>
+        <#if helper.isCountArrayField(field)>
         // Count array
-        int _${field.name}Count = ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}Count];
-        for(int i = 0; i < _${field.name}Count; i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)});
+        int _${manualArrayField.name}Count = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.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, type.parserArguments)});
         }
         <#-- In all other cases do we have to work with a list, that is later converted to an array -->
         <#else>
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-            <#if helper.isLengthArray(field)>
+            <#if helper.isLengthArrayField(field)>
         // Length array
-        int _${field.name}Length = ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        int ${field.name}EndPos = io.getPos() + _${field.name}Length;
-        while(io.getPos() < ${field.name}EndPos) {
-            _${field.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)}));
+        int _${manualArrayField.name}Length = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)};
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
+        int ${manualArrayField.name}EndPos = io.getPos() + _${manualArrayField.name}Length;
+        while(io.getPos() < ${manualArrayField.name}EndPos) {
+            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)}));
             <#-- After parsing, update the current position, but only if it's needed -->
-            <#if field.loopExpression.contains("curPos")>
+            <#if manualArrayField.loopExpression.contains("curPos")>
             curPos = io.getPos() - startPos;
             </#if>
         }
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-            <#elseif helper.isTerminatedArray(field)>
+            <#elseif helper.isTerminatedArrayField(field)>
         // Terminated array
-        List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)}))) {
-            _${field.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)}));
+        List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
+        while(!((boolean) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)}))) {
+            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)}));
 
             <#-- After parsing, update the current position, but only if it's needed -->
-            <#if field.loopExpression.contains("curPos")>
+            <#if manualArrayField.loopExpression.contains("curPos")>
             curPos = io.getPos() - startPos;
             </#if>
         }
@@ -264,62 +304,72 @@ public class ${typeName}IO implements <#if outputFlavor != "passive">MessageIO<$
                 type we have to iterate over it's elements and explicitly cast them.
                 Otherwise a simple toArray call is fine.
             -->
-            <#if helper.isSimpleType(field.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}List.size()];
-        for(int i = 0; i < _${field.name}List.size(); i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${field.name}List.get(i);
+            <#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)}[] ${field.name} = _${field.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(field)}[0]);
+        ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = _${manualArrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}[0]);
             </#if>
         </#if>
         <#break>
     <#case "manual">
+        <#assign manualField = field>
 
-        // Manual Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)});
+        // Manual Field (${manualField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, type.parserArguments)});
         <#break>
     <#case "optional">
+        <#assign optionalField = field>
 
-        // Optional Field (${field.name}) (Can be skipped, if a given expression evaluates to false)
-        <#if field.conditionExpression.contains("curPos")>
+        // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
+        <#if optionalField.conditionExpression.contains("curPos")>
         curPos = io.getPos() - startPos;
         </#if>
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = null;
-        if(${helper.toParseExpression(field, field.conditionExpression, type.parserArguments)?no_esc}) {
-            ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+        ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null;
+        if(${helper.toParseExpression(optionalField, optionalField.conditionExpression, type.parserArguments)}) {
+            ${optionalField.name} = <#if helper.isSimpleTypeReference(optionalField.type)>${helper.getReadBufferReadMethodCall(optionalField.type)}<#else>${optionalField.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(optionalField.type, parserArgument?index), true)}) (${helper.toParseExpression(optionalField, parserArgument, type.parserArguments)})<#sep>, </#sep></#list> [...]
         }
         <#break>
     <#case "padding">
+        <#assign paddingField = field>
+        <#assign simpleTypeReference = paddingField.type>
 
-        // Padding Field (${field.name})
-        boolean _${field.name}NeedsPadding = (boolean) ((io.hasMore(${helper.getNumBits(field.type)})) && (${helper.toParseExpression(field, field.paddingCondition, type.parserArguments)?no_esc}));
-        if(_${field.name}NeedsPadding) {
-            // Just read the padding data and ignore it
-            ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
+        // Padding Field (padding)
+        {
+            boolean _needsPadding = (boolean) ((io.hasMore(${helper.getNumBits(simpleTypeReference)})) && (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)}));
+            if(_needsPadding) {
+                // Just read the padding data and ignore it
+                ${helper.getReadBufferReadMethodCall(simpleTypeReference)};
+            }
         }
         <#break>
     <#case "reserved">
+        <#assign reservedField = field>
+        <#assign simpleTypeReference = reservedField.type>
 
         // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
         {
-            ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(field.type)?no_esc};
-            if(reserved != ${helper.getReservedValue(field)}) {
-                LOGGER.info("Expected constant value " + ${field.referenceValue} + " but got " + reserved + " for reserved field.");
+            ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(simpleTypeReference)};
+            if(reserved != ${helper.getReservedValue(reservedField)}) {
+                LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field.");
             }
         }
         <#break>
     <#case "simple">
+        <#assign simpleField = field>
 
-        // Simple Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleType(field.type)>${helper.getReadBufferReadMethodCall(field.type)?no_esc}<#else>${field.type.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getArgumentType(field.type, parserArgument?index)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+        // Simple Field (${simpleField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = <#if helper.isSimpleTypeReference(simpleField.type)><#assign simpleTypeReference = simpleField.type>${helper.getReadBufferReadMethodCall(simpleTypeReference)}<#else><#assign complexTypeReference = simpleField.type>${complexTypeReference.name}IO.staticParse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleField.type, p [...]
         <#break>
     <#case "switch">
+        <#assign switchField = field>
 
         // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
-        ${typeName}Builder builder = null;
-        <#list field.cases as case>
-        <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(field.discriminatorExpressions[discriminatorValue?index])?no_esc}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{
+        ${type.name}Builder builder = null;
+        <#list switchField.cases as case>
+        <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{
             builder = ${case.name}IO.staticParse(io<#if case.parserArguments?has_content>, <#list case.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
         }<#sep> else </#sep>
         </#list>
@@ -329,169 +379,201 @@ public class ${typeName}IO implements <#if outputFlavor != "passive">MessageIO<$
         <#break>
 
     <#case "virtual">
+        <#assign virtualField = field>
 
         // Virtual field (Just declare a local variable so we can access it in the parser)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.valueExpression, type.parserArguments)});
+        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)});
         <#break>
 </#switch>
 </#list>
 
         // Create the instance
-        <#if helper.isDiscriminatedType(type)>
-        return new ${typeName}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
-        <#elseif type.abstract>
+        <#if helper.isDiscriminatedChildTypeDefinition()>
+        return new ${type.name}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+        <#elseif helper.isDiscriminatedParentTypeDefinition()>
         return builder.build(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
         <#else>
-        return new ${typeName}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+        return new ${type.name}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
         </#if>
     }
 
 <#if outputFlavor != "passive">
-    public static void staticSerialize(WriteBuffer io, ${typeName} _value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static void staticSerialize(WriteBuffer io, ${type.name} _value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         int startPos = io.getPos();
 
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
+        <#assign arrayField = field>
+        <#assign simpleTypeReference = arrayField.type>
 
-        // Array Field (${field.name})
-        if(_value.get${field.name?cap_first}() != null) {
-            int itemCount = (int) _value.get${field.name?cap_first}().length;
+        // Array Field (${arrayField.name})
+        if(_value.get${arrayField.name?cap_first}() != null) {
+            int itemCount = (int) _value.get${arrayField.name?cap_first}().length;
             int curItem = 0;
-            for(${helper.getLanguageTypeNameForField(field)} element : _value.get${field.name?cap_first}()) {
-                <#if helper.isSimpleType(field.type)>
-                ${helper.getWriteBufferReadMethodCall(field.type, "element")?no_esc};
+            for(${helper.getLanguageTypeNameForField(field)} element : _value.get${arrayField.name?cap_first}()) {
+                <#if helper.isSimpleTypeReference(arrayField.type)>
+                    <#assign simpleTypeReference = arrayField.type>
+                ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "element")};
                 <#else>
+                    <#assign complexTypeReference = arrayField.type>
                 boolean lastItem = curItem == (itemCount - 1);
-                ${field.type.name}IO.staticSerialize(io, element<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+                ${complexTypeReference.name}IO.staticSerialize(io, element<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
                 </#if>
                 curItem++;
             }
         }
         <#break>
     <#case "checksum">
+        <#assign checksumField = field>
+        <#assign simpleTypeReference = checksumField.type>
 
-        // Checksum Field (${field.name}) (Calculated)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForType(field.type)};
+        // Checksum Field (checksum) (Calculated)
         {
+            ${helper.getLanguageTypeNameForField(field)} _checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
             // Create an array of all the bytes written in this message element so far.
             byte[] checksumRawData = io.getBytes(startPos, io.getPos());
-            ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(field, field.checksumExpression, type.parserArguments)?no_esc});
-            ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
+            _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, type.parserArguments)});
+            ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "(_checksum)")};
         }
         <#break>
     <#case "const">
+        <#assign constField = field>
+        <#assign simpleTypeReference = constField.type>
 
-        // Const Field (${field.name})
-        ${helper.getWriteBufferReadMethodCall(field.type, field.referenceValue)?no_esc};
+        // Const Field (${constField.name})
+        ${helper.getWriteBufferReadMethodCall(simpleTypeReference, constField.referenceValue)};
         <#break>
     <#case "discriminator">
+        <#assign discriminatorField = field>
+        <#assign simpleTypeReference = discriminatorField.type>
 
-        // Discriminator Field (${field.name}) (Used as input to a switch field)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.getDiscriminatorValues()[0];
-        ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
+        // 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}();
+        ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "(" + discriminatorField.name + ")")};
         <#break>
     <#case "enum">
+        <#assign enumField = field>
 
-        // Enum field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${field.name?cap_first}();
-        ${helper.getWriteBufferReadMethodCall(helper.getEnumBaseType(field.type), "(" + field.name + ".getValue())")?no_esc};
+        // Enum field (${enumField.name})
+        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${enumField.name?cap_first}();
+        ${helper.getWriteBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type), "(" + enumField.name + ".getValue())")};
         <#break>
     <#case "implicit">
+        <#assign implicitField = field>
+        <#assign simpleTypeReference = implicitField.type>
 
-        // Implicit Field (${field.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(field, field.serializeExpression, type.parserArguments)?no_esc});
-        ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
+        // 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, type.parserArguments)});
+        ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "(" + implicitField.name + ")")};
         <#break>
     <#case "manualArray">
+        <#assign manualArrayField = field>
 
-        // Manual Array Field (${field.name})
-        if(_value.get${field.name?cap_first}() != null) {
-            for(${helper.getLanguageTypeNameForField(field)} element : _value.get${field.name?cap_first}()) {
-                ${helper.toSerializationExpression(field ,field.serializeExpression, type.parserArguments)?no_esc};
+        // Manual Array Field (${manualArrayField.name})
+        if(_value.get${manualArrayField.name?cap_first}() != null) {
+            for(${helper.getLanguageTypeNameForField(field)} element : _value.get${manualArrayField.name?cap_first}()) {
+                ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, type.parserArguments)};
             }
         }
         <#break>
     <#case "manual">
+        <#assign manualField = field>
 
-        // Manual Field (${field.name})
-        ${helper.toSerializationExpression(field ,field.serializeExpression, type.parserArguments)?no_esc};
+        // Manual Field (${manualField.name})
+        ${helper.toSerializationExpression(manualField, manualField.serializeExpression, type.parserArguments)};
        <#break>
     <#case "optional">
-
-        // Optional Field (${field.name}) (Can be skipped, if the value is null)
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = null;
-        if(_value.get${field.name?cap_first}() != null) {
-            ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${field.name?cap_first}();
-            <#if helper.isSimpleType(field.type)>
-            ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
+        <#assign optionalField = field>
+
+        // 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>
+            ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "(" + optionalField.name + ")")};
             <#else>
-            ${field.type.name}IO.staticSerialize(io, ${field.name});
+                <#assign complexTypeReference = optionalField.type>
+            ${complexTypeReference.name}IO.staticSerialize(io, ${optionalField.name});
             </#if>
         }
         <#break>
     <#case "padding">
+        <#assign paddingField = field>
+        <#assign simpleTypeReference = paddingField.type>
 
-        // Padding Field (${field.name})
-        boolean _${field.name}NeedsPadding = (boolean) (${helper.toSerializationExpression(field, field.paddingCondition, type.parserArguments)?no_esc});
-        if(_${field.name}NeedsPadding) {
-            ${helper.getLanguageTypeNameForField(field)} _${field.name}PaddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(field, field.paddingValue, type.parserArguments)?no_esc});
-            ${helper.getWriteBufferReadMethodCall(field.type, "(_" + field.name + "PaddingValue)")?no_esc};
+        // Padding Field (padding)
+        {
+            boolean _needsPadding = (boolean) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)});
+            if(_needsPadding) {
+                ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, type.parserArguments)});
+                ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "(_paddingValue)")};
+            }
         }
         <#break>
     <#case "reserved">
+        <#assign reservedField = field>
+        <#assign simpleTypeReference = reservedField.type>
 
-        // Reserved Field
-        ${helper.getWriteBufferReadMethodCall(field.type, helper.getReservedValue(field))?no_esc};
+        // Reserved Field (reserved)
+        ${helper.getWriteBufferReadMethodCall(simpleTypeReference, helper.getReservedValue(field))};
         <#break>
     <#case "simple">
+        <#assign simpleField = field>
 
-        // Simple Field (${field.name})
-        ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${field.name?cap_first}();
-        <#if helper.isSimpleType(field.type)>
-        ${helper.getWriteBufferReadMethodCall(field.type, "(" + field.name + ")")?no_esc};
+        // 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>
+            ${helper.getWriteBufferReadMethodCall(simpleTypeReference, "(" + simpleField.name + ")")};
         <#else>
-        ${field.type.name}IO.staticSerialize(io, ${field.name});
+            <#assign complexTypeReference = simpleField.type>
+        ${complexTypeReference.name}IO.staticSerialize(io, ${simpleField.name});
         </#if>
         <#break>
     <#case "switch">
+        <#assign switchField = field>
 
         // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
-        <#list field.cases as case>
+        <#list switchField.cases as case>
         if(_value instanceof ${case.name}) {
             ${case.name}IO.staticSerialize(io, (${case.name}) _value);
         }<#sep> else </#sep>
         </#list>
         <#break>
+    <#case "virtual">
+        <#break>
 </#switch>
 </#list>
     }
 </#if>
 
-<#if type.abstract>
-    public static interface ${typeName}Builder {
-        ${typeName} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>);
+<#if helper.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 helper.isDiscriminatedType(type)>
-    public static class ${typeName}Builder implements ${type.parentType.name}IO.${type.parentType.name}Builder {
+<#if helper.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 ${typeName}Builder(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+        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 ${typeName} build(<#list type.parentType.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
-            return new ${typeName}(<#list type.getAllPropertyFields() as field>${field.name}<#sep>, </#sep></#list>);
+        public ${type.name} build(<#list type.parentType.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+            return new ${type.name}(<#list type.getAllPropertyFields() as field>${field.name}<#sep>, </#sep></#list>);
         }
     }
 
 </#if>
-}
\ No newline at end of file
+}
+</#outputformat>
\ No newline at end of file
diff --git a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
index 3697670..43da35d 100644
--- a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
@@ -16,7 +16,32 @@
   specific language governing permissions and limitations
   under the License.
 -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${typeName}.java
+<#-- 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="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
 /*
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -55,18 +80,41 @@ import java.util.*;
 import java.math.BigInteger;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??> extends ${type.parentType.name}</#if> implements Message {
+public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.parentType??> extends ${type.parentType.name}</#if> implements Message {
 
-<#if helper.isDiscriminatedType(type)>
-
-    // Discriminator values used by the parser to determine the type to be used. All values have to apply.
-    public static final Object[] DISCRIMINATOR_VALUES = new Object[] {
-    <#list type.discriminatorValues as discriminatorValue>
-        <#-- There are rare occasions where the discriminator is defined by a parser argument, in this case we currently can't detect the type -->
-        (${helper.getDiscriminatorConstantType(type, discriminatorValue?index)}) ${discriminatorValue}<#sep>, </#sep>
+<#--
+    If this is a discriminated child type, we need to generate methods for accessing it's discriminator
+    values, as if they were normal java properties.
+-->
+<#if helper.isDiscriminatedChildTypeDefinition()>
+    <#assign discriminatedChildType = type>
+    <#-- @ftlvariable name="discriminatedChildType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.DiscriminatedComplexTypeDefinition" -->
+    // Accessors for discriminator values.
+    <#list helper.getDiscriminatorValues(discriminatedChildType) as discriminatorName, discriminatorValue>
+        <#-- If the discriminator name matches that of another field, suppress the methods generation -->
+        <#if !helper.isNonDiscriminatorField(discriminatorName)>
+    public ${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])} get${discriminatorName?cap_first}() {
+        return <#if discriminatorValue??>${discriminatorValue}<#else>${helper.getNullValueForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])}</#if>;
+    }
+        </#if>
+    </#list>
+</#if>
+<#--
+    If this is a discriminated parent type, we need to generate the abstract methods for accessing it's
+    discriminator values instead.
+-->
+<#if helper.isDiscriminatedParentTypeDefinition()>
+    <#assign discriminatedParentType = type>
+    <#-- @ftlvariable name="discriminatedParentType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+    // Abstract accessors for discriminator values.
+    <#list helper.getDiscriminatorTypes() as discriminatorName, discriminatorType>
+        <#-- If the discriminator name matches that of another field, suppress the methods generation -->
+        <#if !helper.isNonDiscriminatorField(discriminatorName)>
+    public abstract ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}();
+        </#if>
     </#list>
-    };
 </#if>
+<#-- If the current type contains "const" fields, generate some java constants for holing their values -->
 <#if type.constFields?has_content>
 
     // Constant values.
@@ -85,7 +133,7 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
     <#-- getAllPropertyFields() returns not only the property fields of this type but also of it's parents -->
-    public ${typeName}(<#list type.getAllPropertyFields() as field>@JsonProperty("${field.name}") ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+    public ${type.name}(<#list type.getAllPropertyFields() as field>@JsonProperty("${field.name}") ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
 <#if type.getParentPropertyFields()?has_content>
         super(<#list type.getParentPropertyFields() as field>${field.name}<#sep>, </#sep></#list>);
 </#if>
@@ -93,17 +141,6 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
         this.${field.name} = ${field.name};
 </#list>
     }
-<#if type.abstract>
-
-    public abstract Object[] getDiscriminatorValues();
-</#if>
-<#if helper.isDiscriminatedType(type)>
-
-    @JsonIgnore
-    public Object[] getDiscriminatorValues() {
-        return DISCRIMINATOR_VALUES;
-    }
-</#if>
 
 <#list type.propertyFields as field>
     <#if helper.isAbstractField(field)>
@@ -134,91 +171,114 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
+        <#assign arrayField = field>
 
         // Array field
-        <#if helper.isSimpleType(field.type)>
-        lengthInBits += ${field.type.sizeInBits} * ${field.name}.length;
+        <#if helper.isSimpleTypeReference(arrayField.type)>
+            <#assign simpleTypeReference = arrayField.type>
+        lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.length;
         <#else>
-        if(${field.name} != null) {
-            for(Message element : ${field.name}) {
+        if(${arrayField.name} != null) {
+            for(Message element : ${arrayField.name}) {
                 lengthInBits += element.getLengthInBits();
             }
         }
         </#if>
         <#break>
     <#case "checksum">
+        <#assign checksumField = field>
+        <#assign simpleTypeReference = checksumField.type>
 
-        // Checksum Field (${field.name})
-        lengthInBits += ${field.type.sizeInBits};
+        // Checksum Field (checksum)
+        lengthInBits += ${simpleTypeReference.sizeInBits};
         <#break>
     <#case "const">
+        <#assign constField = field>
+        <#assign simpleTypeReference = constField.type>
 
-        // Const Field (${field.name})
-        lengthInBits += ${field.type.sizeInBits};
+        // Const Field (${constField.name})
+        lengthInBits += ${simpleTypeReference.sizeInBits};
         <#break>
     <#case "discriminator">
+        <#assign discriminatorField = field>
+        <#assign simpleTypeReference = discriminatorField.type>
 
-        // Discriminator Field (${field.name})
-        lengthInBits += ${field.type.sizeInBits};
+        // Discriminator Field (${discriminatorField.name})
+        lengthInBits += ${simpleTypeReference.sizeInBits};
         <#break>
     <#case "enum">
+        <#assign enumField = field>
 
-        // Enum Field (${field.name})
-        lengthInBits += ${helper.getEnumBaseType(field.type).sizeInBits};
+        // Enum Field (${enumField.name})
+        lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
         <#break>
     <#case "implicit">
+        <#assign implicitField = field>
+        <#assign simpleTypeReference = implicitField.type>
 
-        // Implicit Field (${field.name})
-        lengthInBits += ${field.type.sizeInBits};
+        // Implicit Field (${implicitField.name})
+        lengthInBits += ${simpleTypeReference.sizeInBits};
         <#break>
     <#case "manualArray">
+        <#assign manualArrayField = field>
 
-        // Manual Array Field (${field.name})
-        lengthInBits += ${helper.toParseExpression(field, field.lengthExpression, null)} * 8;
+        // Manual Array Field (${manualArrayField.name})
+        lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, type.parserArguments)} * 8;
         <#break>
     <#case "manual">
+        <#assign manualField = field>
 
-        // Manual Field (${field.name})
-        lengthInBits += ${helper.toParseExpression(field, field.lengthExpression, null)} * 8;
+        // Manual Field (${manualField.name})
+        lengthInBits += ${helper.toParseExpression(manualField, manualField.lengthExpression, type.parserArguments)} * 8;
         <#break>
     <#case "optional">
+        <#assign optionalField = field>
 
-        // Optional Field (${field.name})
-        if(${field.name} != null) {
-        <#if helper.isSimpleType(field.type)>
-            lengthInBits += ${field.type.sizeInBits};
+        // Optional Field (${optionalField.name})
+        if(${optionalField.name} != null) {
+        <#if helper.isSimpleTypeReference(optionalField.type)>
+            <#assign simpleTypeReference = optionalField.type>
+            lengthInBits += ${simpleTypeReference.sizeInBits};
         <#else>
-            lengthInBits += ${field.name}.getLengthInBits();
+            lengthInBits += ${optionalField.name}.getLengthInBits();
         </#if>
         }
         <#break>
     <#case "padding">
+        <#assign paddingField = field>
+        <#assign simpleTypeReference = paddingField.type>
 
-        // Padding Field (${field.name})
+        // Padding Field (padding)
         <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
-        if((boolean) (${helper.toParseExpression(field, field.paddingCondition, type.parserArguments)?replace("lastItem", "false")?no_esc})) {
-            lengthInBits += ${field.type.sizeInBits};
+        if((boolean) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)?replace("lastItem", "false")})) {
+            lengthInBits += ${simpleTypeReference.sizeInBits};
         }
         <#break>
     <#case "reserved">
+        <#assign reservedField = field>
+        <#assign simpleTypeReference = reservedField.type>
 
-        // Reserved Field
-        lengthInBits += ${field.type.sizeInBits};
+        // Reserved Field (reserved)
+        lengthInBits += ${simpleTypeReference.sizeInBits};
         <#break>
     <#case "simple">
+        <#assign simpleField = field>
 
-        // Simple field (${field.name})
-        <#if helper.isSimpleType(field.type)>
-        lengthInBits += ${field.type.sizeInBits};
+        // Simple field (${simpleField.name})
+        <#if helper.isSimpleTypeReference(simpleField.type)>
+            <#assign simpleTypeReference = simpleField.type>
+        lengthInBits += ${simpleTypeReference.sizeInBits};
         <#else>
-        lengthInBits += ${field.name}.getLengthInBits();
+        lengthInBits += ${simpleField.name}.getLengthInBits();
         </#if>
         <#break>
     <#case "switch">
+        <#assign switchField = field>
 
         // Length of sub-type elements will be added by sub-type...
         <#break>
     <#case "virtual">
+        <#assign virtualField = field>
 
         // A virtual field doesn't have any in- or output.
         <#break>
@@ -234,54 +294,82 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 <#list type.propertyFields as field>
 <#switch field.typeName>
 <#case "array">
+    <#assign arrayField = field>
+
+        {
+            List<PlcValue> plcValues = new ArrayList<>(${arrayField.name}.length);
+            for(${helper.getLanguageTypeNameForField(field)} item : ${arrayField.name}) {
+        <#if helper.isSimpleTypeReference(arrayField.type)>
+                plcValues.add(PlcValues.of(item));
+        <#else>
+                plcValues.add(item.toPlcValue());
+        </#if>
+            }
+            fieldValues.put("${arrayField.name}", new PlcList(plcValues));
+        }
+    <#break>
 <#case "manualArray">
+    <#assign manualArrayField = field>
 
         {
-            List<PlcValue> plcValues = new ArrayList<>(${field.name}.length);
-            for(${helper.getLanguageTypeNameForField(field)} item : ${field.name}) {
-                <#if helper.isSimpleType(field.type)>
+            List<PlcValue> plcValues = new ArrayList<>(${manualArrayField.name}.length);
+            for(${helper.getLanguageTypeNameForField(field)} item : ${manualArrayField.name}) {
+                <#if helper.isSimpleTypeReference(manualArrayField.type)>
                 plcValues.add(PlcValues.of(item));
                 <#else>
                 plcValues.add(item.toPlcValue());
                 </#if>
             }
-            fieldValues.put("${field.name}", new PlcList(plcValues));
+            fieldValues.put("${manualArrayField.name}", new PlcList(plcValues));
         }
 <#break>
 <#case "enum">
+    <#assign enumField = field>
 
-        fieldValues.put("${field.name}", new PlcString(${field.name}.name()));
+        fieldValues.put("${enumField.name}", new PlcString(${enumField.name}.name()));
 <#break>
 <#case "manual">
+    <#assign manualField = field>
+
+    <#if helper.isSimpleTypeReference(manualField.type)>
+        fieldValues.put("${manualField.name}", PlcValues.of(${manualField.name}));
+    <#else>
+        fieldValues.put("${manualField.name}", ${manualField.name}.toPlcValue());
+    </#if>
+<#break>
 <#case "simple">
+    <#assign simpleField = field>
 
-    <#if helper.isSimpleType(field.type)>
-        fieldValues.put("${field.name}", PlcValues.of(${field.name}));
+    <#if helper.isSimpleTypeReference(simpleField.type)>
+        fieldValues.put("${simpleField.name}", PlcValues.of(${simpleField.name}));
     <#else>
-        fieldValues.put("${field.name}", ${field.name}.toPlcValue());
+        fieldValues.put("${simpleField.name}", ${simpleField.name}.toPlcValue());
     </#if>
 <#break>
 <#case "optional">
+    <#assign optionalField = field>
 
-        if(${field.name} != null) {
-            <#if helper.isSimpleType(field.type)>
-            fieldValues.put("${field.name}", PlcValues.of(${field.name}));
+        if(${optionalField.name} != null) {
+            <#if helper.isSimpleTypeReference(optionalField.type)>
+            fieldValues.put("${optionalField.name}", PlcValues.of(${optionalField.name}));
             <#else>
-            fieldValues.put("${field.name}", ${field.name}.toPlcValue());
+            fieldValues.put("${optionalField.name}", ${optionalField.name}.toPlcValue());
             </#if>
         } else {
-            fieldValues.put("${field.name}", null);
+            fieldValues.put("${optionalField.name}", null);
         }
 <#break>
 <#case "switch">
+    <#assign switchField = field>
 
         PlcStruct superStruct = (PlcStruct) super.toPlcValue();
         fieldValues.putAll(superStruct.getStruct());
 <#break>
 <#case "virtual">
-    <#if helper.isSimpleType(field.type)>
+    <#assign virtualField = field>
+    <#if helper.isSimpleTypeReference(virtualField.type)>
 
-        fieldValues.put("${field.name}", PlcValues.of(${field.name}));
+        fieldValues.put("${virtualField.name}", PlcValues.of(${virtualField.name}));
     </#if>
 <#break>
 </#switch>
@@ -295,8 +383,8 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 
     @Override
     @JsonIgnore
-    public MessageIO<<#if type.parentType??>${type.parentType.name}<#else>${typeName}</#if>, <#if type.parentType??>${type.parentType.name}<#else>${typeName}</#if>> getMessageIO() {
-        return new <#if type.parentType??>${type.parentType.name}<#else>${typeName}</#if>IO();
+    public MessageIO<<#if type.parentType??>${type.parentType.name}<#else>${type.name}</#if>, <#if type.parentType??>${type.parentType.name}<#else>${type.name}</#if>> getMessageIO() {
+        return new <#if type.parentType??>${type.parentType.name}<#else>${type.name}</#if>IO();
     }
 
     @Override
@@ -304,10 +392,10 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
         if (this == o) {
             return true;
         }
-        if (!(o instanceof ${typeName})) {
+        if (!(o instanceof ${type.name})) {
             return false;
         }
-        ${typeName} that = (${typeName}) o;
+        ${type.name} that = (${type.name}) o;
         return
             <#if type.propertyFields?has_content>
             <#list type.propertyFields as field>
@@ -355,4 +443,5 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
             .toString();
     }
 
-}
\ No newline at end of file
+}
+</#outputformat>
\ No newline at end of file
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
index 55369b2..de2a29f 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
@@ -124,19 +124,19 @@ public class StaticHelper {
 
     }
 
-    public static String parseS7String(ReadBuffer io, String encoding) {
+    public static String parseS7String(ReadBuffer io, Object encoding) {
         try {
             // This is the maximum number of bytes a string can be long.
             short maxLength = io.readUnsignedShort(8);
             // This is the total length of the string on the PLC (Not necessarily the number of characters read)
             short totalStringLength = io.readShort(8);
-            return io.readString(8 * totalStringLength, encoding);
+            return io.readString(8 * totalStringLength, (String) encoding);
         } catch (ParseException e) {
             return null;
         }
     }
 
-    public static void serializeS7String(WriteBuffer io, PlcValue value, String encoding) {
+    public static void serializeS7String(WriteBuffer io, PlcValue value, Object encoding) {
         // TODO: Need to implement the serialization or we can't write strings
         throw new PlcRuntimeException("Not implemented yet");
     }
diff --git a/protocols/eip/src/main/resources/protocols/eip/eip.mspec b/protocols/eip/src/main/resources/protocols/eip/eip.mspec
index 3b03462..b772ff1 100644
--- a/protocols/eip/src/main/resources/protocols/eip/eip.mspec
+++ b/protocols/eip/src/main/resources/protocols/eip/eip.mspec
@@ -97,8 +97,8 @@
                [reserved   uint    8   '0x24']   // setRequestPathLogicalInstanceSegment
                [reserved   uint    8   '0x01']   // setRequestPathInstance
                [reserved   uint    16  '0x9D05']   //Timeout 5s
-               [implicit   uint    16   'messageSize'   'lengthInBytes - 10 - 4']   //substract above and routing
-               [simple     CipService  'service' ['messageSize'] ]
+               [implicit   uint    16  'messageSize'   'lengthInBytes - 10 - 4']   //subtract above and routing
+               [simple     CipService  'unconnectedService' ['messageSize'] ]
                [const      uint    16  'route' '0x0001']
                [simple     int     8   'backPlane']
                [simple     int     8   'slot']
diff --git a/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec b/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec
index 6d57b6c..20f88ad 100644
--- a/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec
+++ b/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec
@@ -57,8 +57,8 @@
 ]
 
 [discriminatedType 'FirmataCommand' [bit 'response']
-    [discriminator uint 4 'command']
-    [typeSwitch 'command'
+    [discriminator uint 4 'commandCode']
+    [typeSwitch 'commandCode'
         ['0x0' FirmataCommandSysex
             [simple SysexCommand 'command' ['response']]
             [reserved uint 8 '0xF7']
diff --git a/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec b/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
index a8a335b..7fa200b 100644
--- a/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
+++ b/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
@@ -293,8 +293,8 @@
 ]
 
 [discriminatedType 'CEMIFrame'
-    [simple        bit          'standardFrame']
-    [simple        bit          'polling']
+    [discriminator bit          'standardFrame']
+    [discriminator bit          'polling']
     [simple        bit          'doNotRepeat']
     [discriminator bit          'notAckFrame']
     [enum          CEMIPriority 'priority']
diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
index 177e4cc..8079176 100644
--- a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -56,8 +56,8 @@
 ]
 
 [discriminatedType 'ModbusPDU' [bit 'response']
-    [implicit       bit         'error'     'DISCRIMINATOR_VALUES[0]']
-    [implicit       uint 7      'function'  'DISCRIMINATOR_VALUES[1]']
+    [discriminator bit         'error']
+    [discriminator uint 7      'function']
     [typeSwitch 'error','function','response'
         ['true'                     ModbusPDUError
             [simple     uint 8      'exceptionCode']
diff --git a/sandbox/plc4c/generated-sources/modbus/includes/modbus_pdu.h b/sandbox/plc4c/generated-sources/modbus/includes/modbus_pdu.h
index eef9471..8623cd7 100644
--- a/sandbox/plc4c/generated-sources/modbus/includes/modbus_pdu.h
+++ b/sandbox/plc4c/generated-sources/modbus/includes/modbus_pdu.h
@@ -25,45 +25,10 @@ extern "C" {
 #include <stdbool.h>
 #include <stdint.h>
 #include <plc4c/utils/list.h>
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu_write_file_record_response_item.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu_read_file_record_response_item.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
 #include "modbus_pdu_write_file_record_request_item.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
-#include "modbus_pdu.h"
 #include "modbus_pdu_read_file_record_request_item.h"
-#include "modbus_pdu.h"
+#include "modbus_pdu_read_file_record_response_item.h"
+#include "modbus_pdu_write_file_record_response_item.h"
 #include "modbus_pdu.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_constants.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_constants.c
index 92b231e..7bf422b 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_constants.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_constants.c
@@ -30,6 +30,7 @@ plc4c_return_code plc4c_modbus_read_write_modbus_constants_parse(plc4c_spi_read_
 
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_constants* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_constants));
+
   // Const Field (modbusTcpDefaultPort)
   uint16_t modbusTcpDefaultPort = plc4c_spi_read_unsigned_int(buf, 16);
   if(modbusTcpDefaultPort != MODBUS_READ_WRITE_MODBUS_CONSTANTS_MODBUS_TCP_DEFAULT_PORT) {
@@ -37,7 +38,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_constants_parse(plc4c_spi_read_
     // throw new ParseException("Expected constant value " + ModbusConstants.MODBUSTCPDEFAULTPORT + " but got " + modbusTcpDefaultPort);
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu.c
index 6c88c36..8843dd8 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu.c
@@ -28,77 +28,77 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_modbus_read_write_modbus_pdu_discriminator plc4c_modbus_read_write_modbus_pdu_discriminators[] = {
   {/* modbus_read_write_modbus_pdu_diagnostic_request */
-   .error = false, .function = 0x08, .response = false},
+   .response = false, .function = 0x08, .error = false},
   {/* modbus_read_write_modbus_pdu_error */
-   .error = true, .function = -1, .response = -1},
+   .response = -1, .function = -1, .error = true},
   {/* modbus_read_write_modbus_pdu_get_com_event_log_request */
-   .error = false, .function = 0x0C, .response = false},
+   .response = false, .function = 0x0C, .error = false},
   {/* modbus_read_write_modbus_pdu_get_com_event_log_response */
-   .error = false, .function = 0x0C, .response = true},
+   .response = true, .function = 0x0C, .error = false},
   {/* modbus_read_write_modbus_pdu_mask_write_holding_register_request */
-   .error = false, .function = 0x16, .response = false},
+   .response = false, .function = 0x16, .error = false},
   {/* modbus_read_write_modbus_pdu_mask_write_holding_register_response */
-   .error = false, .function = 0x16, .response = true},
+   .response = true, .function = 0x16, .error = false},
   {/* modbus_read_write_modbus_pdu_read_coils_request */
-   .error = false, .function = 0x01, .response = false},
+   .response = false, .function = 0x01, .error = false},
   {/* modbus_read_write_modbus_pdu_read_coils_response */
-   .error = false, .function = 0x01, .response = true},
+   .response = true, .function = 0x01, .error = false},
   {/* modbus_read_write_modbus_pdu_read_device_identification_request */
-   .error = false, .function = 0x2B, .response = false},
+   .response = false, .function = 0x2B, .error = false},
   {/* modbus_read_write_modbus_pdu_read_device_identification_response */
-   .error = false, .function = 0x2B, .response = true},
+   .response = true, .function = 0x2B, .error = false},
   {/* modbus_read_write_modbus_pdu_read_discrete_inputs_request */
-   .error = false, .function = 0x02, .response = false},
+   .response = false, .function = 0x02, .error = false},
   {/* modbus_read_write_modbus_pdu_read_discrete_inputs_response */
-   .error = false, .function = 0x02, .response = true},
+   .response = true, .function = 0x02, .error = false},
   {/* modbus_read_write_modbus_pdu_read_exception_status_request */
-   .error = false, .function = 0x07, .response = false},
+   .response = false, .function = 0x07, .error = false},
   {/* modbus_read_write_modbus_pdu_read_exception_status_response */
-   .error = false, .function = 0x07, .response = true},
+   .response = true, .function = 0x07, .error = false},
   {/* modbus_read_write_modbus_pdu_read_fifo_queue_request */
-   .error = false, .function = 0x18, .response = false},
+   .response = false, .function = 0x18, .error = false},
   {/* modbus_read_write_modbus_pdu_read_fifo_queue_response */
-   .error = false, .function = 0x18, .response = true},
+   .response = true, .function = 0x18, .error = false},
   {/* modbus_read_write_modbus_pdu_read_file_record_request */
-   .error = false, .function = 0x14, .response = false},
+   .response = false, .function = 0x14, .error = false},
   {/* modbus_read_write_modbus_pdu_read_file_record_response */
-   .error = false, .function = 0x14, .response = true},
+   .response = true, .function = 0x14, .error = false},
   {/* modbus_read_write_modbus_pdu_read_holding_registers_request */
-   .error = false, .function = 0x03, .response = false},
+   .response = false, .function = 0x03, .error = false},
   {/* modbus_read_write_modbus_pdu_read_holding_registers_response */
-   .error = false, .function = 0x03, .response = true},
+   .response = true, .function = 0x03, .error = false},
   {/* modbus_read_write_modbus_pdu_read_input_registers_request */
-   .error = false, .function = 0x04, .response = false},
+   .response = false, .function = 0x04, .error = false},
   {/* modbus_read_write_modbus_pdu_read_input_registers_response */
-   .error = false, .function = 0x04, .response = true},
+   .response = true, .function = 0x04, .error = false},
   {/* modbus_read_write_modbus_pdu_read_write_multiple_holding_registers_request */
-   .error = false, .function = 0x17, .response = false},
+   .response = false, .function = 0x17, .error = false},
   {/* modbus_read_write_modbus_pdu_read_write_multiple_holding_registers_response */
-   .error = false, .function = 0x17, .response = true},
+   .response = true, .function = 0x17, .error = false},
   {/* modbus_read_write_modbus_pdu_report_server_id_request */
-   .error = false, .function = 0x11, .response = false},
+   .response = false, .function = 0x11, .error = false},
   {/* modbus_read_write_modbus_pdu_report_server_id_response */
-   .error = false, .function = 0x11, .response = true},
+   .response = true, .function = 0x11, .error = false},
   {/* modbus_read_write_modbus_pdu_write_file_record_request */
-   .error = false, .function = 0x15, .response = false},
+   .response = false, .function = 0x15, .error = false},
   {/* modbus_read_write_modbus_pdu_write_file_record_response */
-   .error = false, .function = 0x15, .response = true},
+   .response = true, .function = 0x15, .error = false},
   {/* modbus_read_write_modbus_pdu_write_multiple_coils_request */
-   .error = false, .function = 0x0F, .response = false},
+   .response = false, .function = 0x0F, .error = false},
   {/* modbus_read_write_modbus_pdu_write_multiple_coils_response */
-   .error = false, .function = 0x0F, .response = true},
+   .response = true, .function = 0x0F, .error = false},
   {/* modbus_read_write_modbus_pdu_write_multiple_holding_registers_request */
-   .error = false, .function = 0x10, .response = false},
+   .response = false, .function = 0x10, .error = false},
   {/* modbus_read_write_modbus_pdu_write_multiple_holding_registers_response */
-   .error = false, .function = 0x10, .response = true},
+   .response = true, .function = 0x10, .error = false},
   {/* modbus_read_write_modbus_pdu_write_single_coil_request */
-   .error = false, .function = 0x05, .response = false},
+   .response = false, .function = 0x05, .error = false},
   {/* modbus_read_write_modbus_pdu_write_single_coil_response */
-   .error = false, .function = 0x05, .response = true},
+   .response = true, .function = 0x05, .error = false},
   {/* modbus_read_write_modbus_pdu_write_single_register_request */
-   .error = false, .function = 0x06, .response = false},
+   .response = false, .function = 0x06, .error = false},
   {/* modbus_read_write_modbus_pdu_write_single_register_response */
-   .error = false, .function = 0x06, .response = true}
+   .response = true, .function = 0x06, .error = false}
 };
 
 // Function returning the discriminator values for a given type constant.
@@ -113,10 +113,11 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_parse(plc4c_spi_read_buffer
 
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_pdu* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_pdu));
-  // Implicit Field (error) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
+
+  // Discriminator Field (error) (Used as input to a switch field)
   bool error = plc4c_spi_read_bit(buf);
 
-  // Implicit Field (function) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
+  // Discriminator Field (function) (Used as input to a switch field)
   unsigned int function = plc4c_spi_read_unsigned_short(buf, 7);
 
   // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
@@ -333,7 +334,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_parse(plc4c_spi_read_buffer
   if((error == false) && (function == 0x2B) && (response == true)) { /* ModbusPDUReadDeviceIdentificationResponse */
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_request_item.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_request_item.c
index f32c60f..dde8ef1 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_request_item.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_request_item.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_read_file_record_request_it
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_pdu_read_file_record_request_item* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_pdu_read_file_record_request_item));
 
+
   // Simple Field (referenceType)
   uint8_t referenceType = plc4c_spi_read_unsigned_short(buf, 8);
   msg->reference_type = referenceType;
@@ -47,7 +48,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_read_file_record_request_it
   uint16_t recordLength = plc4c_spi_read_unsigned_int(buf, 16);
   msg->record_length = recordLength;
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_response_item.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_response_item.c
index 8424aeb..c90b073 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_response_item.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_read_file_record_response_item.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_read_file_record_response_i
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_pdu_read_file_record_response_item* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_pdu_read_file_record_response_item));
 
+
   // Implicit Field (dataLength) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
   uint8_t dataLength = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -49,7 +50,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_read_file_record_response_i
     }
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_request_item.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_request_item.c
index 5fe4ade..1ff3404 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_request_item.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_request_item.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_write_file_record_request_i
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_pdu_write_file_record_request_item* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_pdu_write_file_record_request_item));
 
+
   // Simple Field (referenceType)
   uint8_t referenceType = plc4c_spi_read_unsigned_short(buf, 8);
   msg->reference_type = referenceType;
@@ -57,7 +58,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_write_file_record_request_i
     }
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_response_item.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_response_item.c
index e54baa6..d577f3e 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_response_item.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_pdu_write_file_record_response_item.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_write_file_record_response_
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_pdu_write_file_record_response_item* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_pdu_write_file_record_response_item));
 
+
   // Simple Field (referenceType)
   uint8_t referenceType = plc4c_spi_read_unsigned_short(buf, 8);
   msg->reference_type = referenceType;
@@ -57,7 +58,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_pdu_write_file_record_response_
     }
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_serial_adu.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_serial_adu.c
index 8083611..cbfca8d 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_serial_adu.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_serial_adu.c
@@ -31,15 +31,16 @@ plc4c_return_code plc4c_modbus_read_write_modbus_serial_adu_parse(plc4c_spi_read
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_serial_adu* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_serial_adu));
 
+
   // Simple Field (transactionId)
   uint16_t transactionId = plc4c_spi_read_unsigned_int(buf, 16);
   msg->transaction_id = transactionId;
 
   // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
   {
-    uint16_t reserved = plc4c_spi_read_unsigned_int(buf, 16);
-    if(reserved != (uint16_t) 0x0000) {
-      printf("Expected constant value '%d' but got '%d' for reserved field.", 0x0000, reserved);
+    uint16_t _reserved = plc4c_spi_read_unsigned_int(buf, 16);
+    if(_reserved != 0x0000) {
+      printf("Expected constant value '%d' but got '%d' for reserved field.", 0x0000, _reserved);
     }
   }
 
@@ -56,7 +57,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_serial_adu_parse(plc4c_spi_read
   plc4c_modbus_read_write_modbus_pdu_parse(buf, response, (void*) &pdu);
   msg->pdu = pdu;
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/modbus/src/modbus_tcp_adu.c b/sandbox/plc4c/generated-sources/modbus/src/modbus_tcp_adu.c
index 314a825..2f1f058 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/modbus_tcp_adu.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/modbus_tcp_adu.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_modbus_read_write_modbus_tcp_adu_parse(plc4c_spi_read_bu
   // Pointer to the parsed data structure.
   plc4c_modbus_read_write_modbus_tcp_adu* msg = malloc(sizeof(plc4c_modbus_read_write_modbus_tcp_adu));
 
+
   // Simple Field (transactionIdentifier)
   uint16_t transactionIdentifier = plc4c_spi_read_unsigned_int(buf, 16);
   msg->transaction_identifier = transactionIdentifier;
@@ -54,7 +55,6 @@ plc4c_return_code plc4c_modbus_read_write_modbus_tcp_adu_parse(plc4c_spi_read_bu
   plc4c_modbus_read_write_modbus_pdu_parse(buf, response, (void*) &pdu);
   msg->pdu = pdu;
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/includes/cotp_packet.h b/sandbox/plc4c/generated-sources/s7/includes/cotp_packet.h
index 5669cec..53add62 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/cotp_packet.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/cotp_packet.h
@@ -26,16 +26,9 @@ extern "C" {
 #include <stdint.h>
 #include <plc4c/utils/list.h>
 #include "cotp_packet.h"
-#include "cotp_packet.h"
-#include "cotp_packet.h"
+#include "s7_message.h"
 #include "cotp_parameter.h"
 #include "cotp_protocol_class.h"
-#include "cotp_protocol_class.h"
-#include "cotp_protocol_class.h"
-#include "s7_message.h"
-#include "cotp_packet.h"
-#include "cotp_packet.h"
-#include "cotp_packet.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
 struct plc4c_s7_read_write_cotp_packet_discriminator {
diff --git a/sandbox/plc4c/generated-sources/s7/includes/cotp_parameter.h b/sandbox/plc4c/generated-sources/s7/includes/cotp_parameter.h
index 9e086aa..d739637 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/cotp_parameter.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/cotp_parameter.h
@@ -27,10 +27,6 @@ extern "C" {
 #include <plc4c/utils/list.h>
 #include "cotp_tpdu_size.h"
 #include "cotp_parameter.h"
-#include "cotp_parameter.h"
-#include "cotp_parameter.h"
-#include "cotp_parameter.h"
-#include "cotp_parameter.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
 struct plc4c_s7_read_write_cotp_parameter_discriminator {
diff --git a/sandbox/plc4c/generated-sources/s7/includes/s7_address.h b/sandbox/plc4c/generated-sources/s7/includes/s7_address.h
index bcd2f29..9b166a1 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/s7_address.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/s7_address.h
@@ -26,8 +26,8 @@ extern "C" {
 #include <stdint.h>
 #include <plc4c/utils/list.h>
 #include "s7_address.h"
-#include "transport_size.h"
 #include "memory_area.h"
+#include "transport_size.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
 struct plc4c_s7_read_write_s7_address_discriminator {
diff --git a/sandbox/plc4c/generated-sources/s7/includes/s7_message.h b/sandbox/plc4c/generated-sources/s7/includes/s7_message.h
index a22beaf..a92a3ce 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/s7_message.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/s7_message.h
@@ -25,12 +25,9 @@ extern "C" {
 #include <stdbool.h>
 #include <stdint.h>
 #include <plc4c/utils/list.h>
-#include "s7_payload.h"
-#include "s7_message.h"
-#include "s7_message.h"
-#include "s7_message.h"
 #include "s7_message.h"
 #include "s7_parameter.h"
+#include "s7_payload.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
 struct plc4c_s7_read_write_s7_message_discriminator {
diff --git a/sandbox/plc4c/generated-sources/s7/includes/s7_parameter.h b/sandbox/plc4c/generated-sources/s7/includes/s7_parameter.h
index c51996e..f3172a4 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/s7_parameter.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/s7_parameter.h
@@ -26,12 +26,6 @@ extern "C" {
 #include <stdint.h>
 #include <plc4c/utils/list.h>
 #include "s7_var_request_parameter_item.h"
-#include "s7_parameter.h"
-#include "s7_parameter.h"
-#include "s7_parameter.h"
-#include "s7_var_request_parameter_item.h"
-#include "s7_parameter.h"
-#include "s7_parameter.h"
 #include "s7_parameter_user_data_item.h"
 #include "s7_parameter.h"
 
diff --git a/sandbox/plc4c/generated-sources/s7/includes/s7_payload.h b/sandbox/plc4c/generated-sources/s7/includes/s7_payload.h
index c059e75..1aa5564 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/s7_payload.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/s7_payload.h
@@ -25,24 +25,16 @@ extern "C" {
 #include <stdbool.h>
 #include <stdint.h>
 #include <plc4c/utils/list.h>
-#include "s7_parameter.h"
-#include "s7_parameter.h"
-#include "s7_parameter.h"
-#include "s7_var_payload_data_item.h"
-#include "s7_payload.h"
-#include "s7_parameter.h"
-#include "s7_payload.h"
-#include "s7_parameter.h"
-#include "s7_var_payload_data_item.h"
 #include "s7_payload_user_data_item.h"
 #include "s7_var_payload_status_item.h"
-#include "s7_payload.h"
+#include "s7_var_payload_data_item.h"
+#include "s7_parameter.h"
 #include "s7_payload.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
 struct plc4c_s7_read_write_s7_payload_discriminator {
   uint8_t messageType;
-  uint8_t parameter_parameterType;
+  uint8_t parameterParameterType;
 };
 typedef struct plc4c_s7_read_write_s7_payload_discriminator plc4c_s7_read_write_s7_payload_discriminator;
 
diff --git a/sandbox/plc4c/generated-sources/s7/includes/s7_payload_user_data_item.h b/sandbox/plc4c/generated-sources/s7/includes/s7_payload_user_data_item.h
index fe22481..4bbe20b 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/s7_payload_user_data_item.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/s7_payload_user_data_item.h
@@ -25,12 +25,11 @@ extern "C" {
 #include <stdbool.h>
 #include <stdint.h>
 #include <plc4c/utils/list.h>
-#include "szl_id.h"
 #include "data_transport_error_code.h"
+#include "data_transport_size.h"
 #include "s7_payload_user_data_item.h"
+#include "szl_id.h"
 #include "szl_data_tree_item.h"
-#include "s7_payload_user_data_item.h"
-#include "data_transport_size.h"
 
 // Structure used to contain the discriminator values for discriminated types using this as a parent
 struct plc4c_s7_read_write_s7_payload_user_data_item_discriminator {
diff --git a/sandbox/plc4c/generated-sources/s7/includes/s7_var_payload_data_item.h b/sandbox/plc4c/generated-sources/s7/includes/s7_var_payload_data_item.h
index 1e8d765..6783105 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/s7_var_payload_data_item.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/s7_var_payload_data_item.h
@@ -25,8 +25,8 @@ extern "C" {
 #include <stdbool.h>
 #include <stdint.h>
 #include <plc4c/utils/list.h>
-#include "data_transport_size.h"
 #include "data_transport_error_code.h"
+#include "data_transport_size.h"
 
 struct plc4c_s7_read_write_s7_var_payload_data_item {
   /* Properties */
diff --git a/sandbox/plc4c/generated-sources/s7/includes/transport_size.h b/sandbox/plc4c/generated-sources/s7/includes/transport_size.h
index 044b4ef..9850c8b 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/transport_size.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/transport_size.h
@@ -24,8 +24,8 @@ extern "C" {
 #endif
 
 #include <stdbool.h>
-#include "transport_size.h"
 #include "data_transport_size.h"
+#include "transport_size.h"
 
 enum plc4c_s7_read_write_transport_size {
   plc4c_s7_read_write_transport_size_BOOL = 0x01,
diff --git a/sandbox/plc4c/generated-sources/s7/src/cotp_packet.c b/sandbox/plc4c/generated-sources/s7/src/cotp_packet.c
index 9e9630d..242d9de 100644
--- a/sandbox/plc4c/generated-sources/s7/src/cotp_packet.c
+++ b/sandbox/plc4c/generated-sources/s7/src/cotp_packet.c
@@ -54,6 +54,7 @@ plc4c_return_code plc4c_s7_read_write_cotp_packet_parse(plc4c_spi_read_buffer* b
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_cotp_packet* msg = malloc(sizeof(plc4c_s7_read_write_cotp_packet));
 
+
   // Implicit Field (headerLength) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
   uint8_t headerLength = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -135,7 +136,6 @@ plc4c_return_code plc4c_s7_read_write_cotp_packet_parse(plc4c_spi_read_buffer* b
     msg->payload = payload;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/cotp_parameter.c b/sandbox/plc4c/generated-sources/s7/src/cotp_parameter.c
index 7a3f295..50bc779 100644
--- a/sandbox/plc4c/generated-sources/s7/src/cotp_parameter.c
+++ b/sandbox/plc4c/generated-sources/s7/src/cotp_parameter.c
@@ -51,6 +51,7 @@ plc4c_return_code plc4c_s7_read_write_cotp_parameter_parse(plc4c_spi_read_buffer
 
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_cotp_parameter* msg = malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
+
   // Discriminator Field (parameterType) (Used as input to a switch field)
   uint8_t parameterType = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -79,7 +80,6 @@ plc4c_return_code plc4c_s7_read_write_cotp_parameter_parse(plc4c_spi_read_buffer
     msg->cotp_parameter_disconnect_additional_information_data = data;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_address.c b/sandbox/plc4c/generated-sources/s7/src/s7_address.c
index 26b02c4..9b2967e 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_address.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_address.c
@@ -43,6 +43,7 @@ plc4c_return_code plc4c_s7_read_write_s7_address_parse(plc4c_spi_read_buffer* bu
 
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_address* msg = malloc(sizeof(plc4c_s7_read_write_s7_address));
+
   // Discriminator Field (addressType) (Used as input to a switch field)
   uint8_t addressType = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -67,7 +68,6 @@ plc4c_return_code plc4c_s7_read_write_s7_address_parse(plc4c_spi_read_buffer* bu
     msg->s7_address_any_bit_address = bitAddress;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_message.c b/sandbox/plc4c/generated-sources/s7/src/s7_message.c
index 40a6095..28056d0 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_message.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_message.c
@@ -50,6 +50,7 @@ plc4c_return_code plc4c_s7_read_write_s7_message_parse(plc4c_spi_read_buffer* bu
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_message* msg = malloc(sizeof(plc4c_s7_read_write_s7_message));
 
+
   // Const Field (protocolId)
   uint8_t protocolId = plc4c_spi_read_unsigned_short(buf, 8);
   if(protocolId != S7_READ_WRITE_S7_MESSAGE_PROTOCOL_ID) {
@@ -62,9 +63,9 @@ plc4c_return_code plc4c_s7_read_write_s7_message_parse(plc4c_spi_read_buffer* bu
 
   // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
   {
-    uint16_t reserved = plc4c_spi_read_unsigned_int(buf, 16);
-    if(reserved != (uint16_t) 0x0000) {
-      printf("Expected constant value '%d' but got '%d' for reserved field.", 0x0000, reserved);
+    uint16_t _reserved = plc4c_spi_read_unsigned_int(buf, 16);
+    if(_reserved != 0x0000) {
+      printf("Expected constant value '%d' but got '%d' for reserved field.", 0x0000, _reserved);
     }
   }
 
@@ -114,7 +115,6 @@ plc4c_return_code plc4c_s7_read_write_s7_message_parse(plc4c_spi_read_buffer* bu
     msg->payload = payload;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_parameter.c b/sandbox/plc4c/generated-sources/s7/src/s7_parameter.c
index 88bfae7..8f84ef2 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_parameter.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_parameter.c
@@ -28,17 +28,17 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_parameter_discriminator plc4c_s7_read_write_s7_parameter_discriminators[] = {
   {/* s7_read_write_s7_parameter_read_var_request */
-   .messageType = 0x01, .parameterType = 0x04},
+   .parameterType = 0x04, .messageType = 0x01},
   {/* s7_read_write_s7_parameter_read_var_response */
-   .messageType = 0x03, .parameterType = 0x04},
+   .parameterType = 0x04, .messageType = 0x03},
   {/* s7_read_write_s7_parameter_setup_communication */
-   .messageType = -1, .parameterType = 0xF0},
+   .parameterType = 0xF0, .messageType = -1},
   {/* s7_read_write_s7_parameter_user_data */
-   .messageType = 0x07, .parameterType = 0x00},
+   .parameterType = 0x00, .messageType = 0x07},
   {/* s7_read_write_s7_parameter_write_var_request */
-   .messageType = 0x01, .parameterType = 0x05},
+   .parameterType = 0x05, .messageType = 0x01},
   {/* s7_read_write_s7_parameter_write_var_response */
-   .messageType = 0x03, .parameterType = 0x05}
+   .parameterType = 0x05, .messageType = 0x03}
 };
 
 // Function returning the discriminator values for a given type constant.
@@ -53,6 +53,7 @@ plc4c_return_code plc4c_s7_read_write_s7_parameter_parse(plc4c_spi_read_buffer*
 
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_parameter* msg = malloc(sizeof(plc4c_s7_read_write_s7_parameter));
+
   // Discriminator Field (parameterType) (Used as input to a switch field)
   uint8_t parameterType = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -88,7 +89,6 @@ plc4c_return_code plc4c_s7_read_write_s7_parameter_parse(plc4c_spi_read_buffer*
     msg->s7_parameter_user_data_items = items;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c b/sandbox/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c
index 34b5f53..b6fad93 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c
@@ -43,6 +43,7 @@ plc4c_return_code plc4c_s7_read_write_s7_parameter_user_data_item_parse(plc4c_sp
 
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_parameter_user_data_item* msg = malloc(sizeof(plc4c_s7_read_write_s7_parameter_user_data_item));
+
   // Discriminator Field (itemType) (Used as input to a switch field)
   uint8_t itemType = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -73,7 +74,6 @@ plc4c_return_code plc4c_s7_read_write_s7_parameter_user_data_item_parse(plc4c_sp
     msg->s7_parameter_user_data_item_cpu_functions_error_code = errorCode;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_payload.c b/sandbox/plc4c/generated-sources/s7/src/s7_payload.c
index 1faf88d..e01077e 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_payload.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_payload.c
@@ -28,13 +28,13 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_payload_discriminator plc4c_s7_read_write_s7_payload_discriminators[] = {
   {/* s7_read_write_s7_payload_read_var_response */
-   .messageType = 0x03, .parameter_parameterType = 0x04},
+   .parameterParameterType = 0x04, .messageType = 0x03},
   {/* s7_read_write_s7_payload_user_data */
-   .messageType = 0x07, .parameter_parameterType = 0x00},
+   .parameterParameterType = 0x00, .messageType = 0x07},
   {/* s7_read_write_s7_payload_write_var_request */
-   .messageType = 0x01, .parameter_parameterType = 0x05},
+   .parameterParameterType = 0x05, .messageType = 0x01},
   {/* s7_read_write_s7_payload_write_var_response */
-   .messageType = 0x03, .parameter_parameterType = 0x05}
+   .parameterParameterType = 0x05, .messageType = 0x03}
 };
 
 // Function returning the discriminator values for a given type constant.
@@ -49,6 +49,7 @@ plc4c_return_code plc4c_s7_read_write_s7_payload_parse(plc4c_spi_read_buffer* bu
 
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_payload* msg = malloc(sizeof(plc4c_s7_read_write_s7_payload));
+
   // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
   if((plc4c_s7_read_write_s7_parameter_get_discriminator(parameter->_type).parameterType == 0x04) && (messageType == 0x03)) { /* S7PayloadReadVarResponse */
     plc4c_list* items;
@@ -67,7 +68,6 @@ plc4c_return_code plc4c_s7_read_write_s7_payload_parse(plc4c_spi_read_buffer* bu
     msg->s7_payload_user_data_items = items;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c b/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
index 885a661..06e2cc5 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
@@ -46,6 +46,7 @@ plc4c_return_code plc4c_s7_read_write_s7_payload_user_data_item_parse(plc4c_spi_
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_payload_user_data_item* msg = malloc(sizeof(plc4c_s7_read_write_s7_payload_user_data_item));
 
+
   // Enum field (returnCode)
   plc4c_s7_read_write_data_transport_error_code returnCode = plc4c_spi_read_byte(buf, 8);
   msg->return_code = returnCode;
@@ -74,7 +75,6 @@ plc4c_return_code plc4c_s7_read_write_s7_payload_user_data_item_parse(plc4c_spi_
     msg->s7_payload_user_data_item_cpu_function_read_szl_response_items = items;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_data_item.c b/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_data_item.c
index 105a0e5..c9e9b03 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_data_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_data_item.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_s7_read_write_s7_var_payload_data_item_parse(plc4c_spi_r
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_var_payload_data_item* msg = malloc(sizeof(plc4c_s7_read_write_s7_var_payload_data_item));
 
+
   // Enum field (returnCode)
   plc4c_s7_read_write_data_transport_error_code returnCode = plc4c_spi_read_byte(buf, 8);
   msg->return_code = returnCode;
@@ -62,7 +63,6 @@ plc4c_return_code plc4c_s7_read_write_s7_var_payload_data_item_parse(plc4c_spi_r
     plc4c_spi_read_unsigned_short(buf, 8);
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_status_item.c b/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_status_item.c
index 11f34d3..ae8ca78 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_status_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_var_payload_status_item.c
@@ -31,11 +31,11 @@ plc4c_return_code plc4c_s7_read_write_s7_var_payload_status_item_parse(plc4c_spi
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_var_payload_status_item* msg = malloc(sizeof(plc4c_s7_read_write_s7_var_payload_status_item));
 
+
   // Enum field (returnCode)
   plc4c_s7_read_write_data_transport_error_code returnCode = plc4c_spi_read_byte(buf, 8);
   msg->return_code = returnCode;
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c b/sandbox/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c
index 6a2cc50..c50fbd6 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c
@@ -43,6 +43,7 @@ plc4c_return_code plc4c_s7_read_write_s7_var_request_parameter_item_parse(plc4c_
 
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_s7_var_request_parameter_item* msg = malloc(sizeof(plc4c_s7_read_write_s7_var_request_parameter_item));
+
   // Discriminator Field (itemType) (Used as input to a switch field)
   uint8_t itemType = plc4c_spi_read_unsigned_short(buf, 8);
 
@@ -52,7 +53,6 @@ plc4c_return_code plc4c_s7_read_write_s7_var_request_parameter_item_parse(plc4c_
     msg->s7_var_request_parameter_item_address_address = address;
   }
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/szl_data_tree_item.c b/sandbox/plc4c/generated-sources/s7/src/szl_data_tree_item.c
index d5b9c23..900598e 100644
--- a/sandbox/plc4c/generated-sources/s7/src/szl_data_tree_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/szl_data_tree_item.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_s7_read_write_szl_data_tree_item_parse(plc4c_spi_read_bu
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_szl_data_tree_item* msg = malloc(sizeof(plc4c_s7_read_write_szl_data_tree_item));
 
+
   // Simple Field (itemIndex)
   uint16_t itemIndex = plc4c_spi_read_unsigned_int(buf, 16);
   msg->item_index = itemIndex;
@@ -59,7 +60,6 @@ plc4c_return_code plc4c_s7_read_write_szl_data_tree_item_parse(plc4c_spi_read_bu
   uint16_t ausbe = plc4c_spi_read_unsigned_int(buf, 16);
   msg->ausbe = ausbe;
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/szl_id.c b/sandbox/plc4c/generated-sources/s7/src/szl_id.c
index 7ab2f80..87edb3e 100644
--- a/sandbox/plc4c/generated-sources/s7/src/szl_id.c
+++ b/sandbox/plc4c/generated-sources/s7/src/szl_id.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_s7_read_write_szl_id_parse(plc4c_spi_read_buffer* buf, p
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_szl_id* msg = malloc(sizeof(plc4c_s7_read_write_szl_id));
 
+
   // Enum field (typeClass)
   plc4c_s7_read_write_szl_module_type_class typeClass = plc4c_spi_read_byte(buf, 4);
   msg->type_class = typeClass;
@@ -43,7 +44,6 @@ plc4c_return_code plc4c_s7_read_write_szl_id_parse(plc4c_spi_read_buffer* buf, p
   plc4c_s7_read_write_szl_sublist sublistList = plc4c_spi_read_byte(buf, 8);
   msg->sublist_list = sublistList;
 
-
   return OK;
 }
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/tpkt_packet.c b/sandbox/plc4c/generated-sources/s7/src/tpkt_packet.c
index 656b44b..f8d9206 100644
--- a/sandbox/plc4c/generated-sources/s7/src/tpkt_packet.c
+++ b/sandbox/plc4c/generated-sources/s7/src/tpkt_packet.c
@@ -31,6 +31,7 @@ plc4c_return_code plc4c_s7_read_write_tpkt_packet_parse(plc4c_spi_read_buffer* b
   // Pointer to the parsed data structure.
   plc4c_s7_read_write_tpkt_packet* msg = malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
 
+
   // Const Field (protocolId)
   uint8_t protocolId = plc4c_spi_read_unsigned_short(buf, 8);
   if(protocolId != S7_READ_WRITE_TPKT_PACKET_PROTOCOL_ID) {
@@ -40,9 +41,9 @@ plc4c_return_code plc4c_s7_read_write_tpkt_packet_parse(plc4c_spi_read_buffer* b
 
   // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
   {
-    uint8_t reserved = plc4c_spi_read_unsigned_short(buf, 8);
-    if(reserved != (uint8_t) 0x00) {
-      printf("Expected constant value '%d' but got '%d' for reserved field.", 0x00, reserved);
+    uint8_t _reserved = plc4c_spi_read_unsigned_short(buf, 8);
+    if(_reserved != 0x00) {
+      printf("Expected constant value '%d' but got '%d' for reserved field.", 0x00, _reserved);
     }
   }
 
@@ -54,7 +55,6 @@ plc4c_return_code plc4c_s7_read_write_tpkt_packet_parse(plc4c_spi_read_buffer* b
   plc4c_s7_read_write_cotp_packet_parse(buf, (len) - (4), (void*) &payload);
   msg->payload = payload;
 
-
   return OK;
 }
 
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
index 81f2e2f..91b41e8 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
@@ -31,7 +31,6 @@ public class DF1Utils {
         short destinationAddress = (short) args[0];
         short sourceAddress = (short) args[1];
         DF1Command command = (DF1Command) args[2];
-        short commandDiscriminatorValues = (short) command.getDiscriminatorValues()[0];
         short status = command.getStatus();
         int transactionCounter = command.getTransactionCounter();
         if(command instanceof DF1UnprotectedReadRequest) {
@@ -40,7 +39,7 @@ public class DF1Utils {
                 WriteBuffer writeBuffer = new WriteBuffer(10, false);
                 writeBuffer.writeUnsignedShort(8, destinationAddress);
                 writeBuffer.writeUnsignedShort(8, sourceAddress);
-                writeBuffer.writeUnsignedShort(8, commandDiscriminatorValues);
+                writeBuffer.writeUnsignedShort(8, command.getCommandCode());
                 writeBuffer.writeUnsignedShort(8, status);
                 writeBuffer.writeUnsignedInt(16, (short) transactionCounter);
                 writeBuffer.writeUnsignedInt(16, (short) unprotectedReadRequest.getAddress());
@@ -60,7 +59,7 @@ public class DF1Utils {
                 WriteBuffer writeBuffer = new WriteBuffer(10, false);
                 writeBuffer.writeUnsignedShort(8, destinationAddress);
                 writeBuffer.writeUnsignedShort(8, sourceAddress);
-                writeBuffer.writeUnsignedShort(8, commandDiscriminatorValues);
+                writeBuffer.writeUnsignedShort(8, command.getCommandCode());
                 writeBuffer.writeUnsignedShort(8, status);
                 writeBuffer.writeUnsignedInt(16, (short) transactionCounter);
                 boolean escape10 = false;