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 2022/02/24 12:46:55 UTC

[plc4x] branch feature/cleaned-up-type-references updated: feat(codegen): Fixed array type handling and data-io code generation

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

cdutz pushed a commit to branch feature/cleaned-up-type-references
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/cleaned-up-type-references by this push:
     new 7c59bc3  feat(codegen): Fixed array type handling and data-io code generation
7c59bc3 is described below

commit 7c59bc310776f4ffc7e4e55e04134f9de0311463
Author: cdutz <ch...@c-ware.de>
AuthorDate: Thu Feb 24 13:46:42 2022 +0100

    feat(codegen): Fixed array type handling and data-io code generation
---
 .../language/java/JavaLanguageTemplateHelper.java  | 14 +++++
 .../templates/java/data-io-template.java.ftlh      |  2 +-
 .../templates/java/enum-template.java.ftlh         | 33 ++++++++++--
 .../templates/java/model-template.java.ftlh        | 59 ++++++++++------------
 .../mspec/model/fields/DefaultArrayField.java      | 15 ++++++
 .../model/fields/DefaultManualArrayField.java      | 15 ++++++
 .../references/DefaultArrayTypeReference.java      | 38 ++++++++++++++
 .../mspec/parser/MessageFormatListener.java        | 14 +++--
 .../src/main/resources/protocols/test/test.mspec   |  8 +--
 pom.xml                                            |  2 +-
 10 files changed, 155 insertions(+), 45 deletions(-)

diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 206964b..c9ec4a2 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -91,6 +91,14 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
 
     public String getLanguageTypeNameForTypeReference(TypeReference typeReference, boolean allowPrimitive) {
         Objects.requireNonNull(typeReference);
+        if (typeReference instanceof ArrayTypeReference) {
+            final ArrayTypeReference arrayTypeReference = (ArrayTypeReference) typeReference;
+            if(arrayTypeReference.getElementTypeReference().isByteBased()) {
+                return getLanguageTypeNameForTypeReference(arrayTypeReference.getElementTypeReference()) + "[]";
+            } else {
+                return "List<" + getLanguageTypeNameForTypeReference(arrayTypeReference.getElementTypeReference()) + ">";
+            }
+        }
         if (!(typeReference instanceof SimpleTypeReference)) {
             return ((NonSimpleTypeReference) typeReference).getName();
         }
@@ -360,6 +368,9 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
             final String languageTypeName = getLanguageTypeNameForTypeReference(typeReference);
             final SimpleTypeReference enumBaseTypeReference = getEnumBaseTypeReference(typeReference);
             return "new DataReaderEnumDefault<>(" + languageTypeName + "::" + resolverMethod + ", " + getDataReaderCall(enumBaseTypeReference) + ")";
+        } else if (typeReference.isArrayTypeReference()) {
+            final ArrayTypeReference arrayTypeReference = typeReference.asArrayTypeReference().orElseThrow();
+            return getDataReaderCall(arrayTypeReference.getElementTypeReference(), resolverMethod);
         } else if (typeReference.isSimpleTypeReference()) {
             SimpleTypeReference simpleTypeReference = typeReference.asSimpleTypeReference().orElseThrow(IllegalStateException::new);
             return getDataReaderCall(simpleTypeReference);
@@ -431,6 +442,9 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         if (typeReference.isSimpleTypeReference()) {
             SimpleTypeReference simpleTypeReference = typeReference.asSimpleTypeReference().orElseThrow(IllegalStateException::new);
             return getDataWriterCall(simpleTypeReference);
+        } else if (typeReference.isArrayTypeReference()) {
+            final ArrayTypeReference arrayTypeReference = typeReference.asArrayTypeReference().orElseThrow();
+            return getDataWriterCall(arrayTypeReference.getElementTypeReference(), fieldName);
         } else if (typeReference.isComplexTypeReference()) {
             return "new DataWriterComplexDefault<>(writeBuffer)";
         } else {
diff --git a/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh
index 39e1639..1be65b3 100644
--- a/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh
@@ -150,7 +150,7 @@ public class ${type.name} {
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
                             <#elseif arrayField.isTerminatedArrayField()>
             // Terminated array
-            List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = new LinkedList<>();
+            ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = new LinkedList<>();
             while(!((boolean) (${helper.toParseExpression(arrayField, helper.boolTypeReference, arrayField.loopExpression,parserArguments)}))) {
                 ${arrayField.name}.add(<#if arrayField.type.isSimpleTypeReference()>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), tru [...]
 
diff --git a/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh
index 4bf9207..d7822c2 100644
--- a/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh
@@ -60,9 +60,36 @@ import java.util.Map;
 
 public enum ${type.name} {
 
-<#list type.enumValues as enumValue>
-    ${enumValue.name}(<#if type.type.isPresent()>(${helper.getLanguageTypeNameForTypeReference(type.type.orElseThrow(), true)}) <#if type.type.orElseThrow().isComplexTypeReference()><#if helper.isEnumTypeReference(type.type.orElseThrow())>${helper.getLanguageTypeNameForTypeReference(type.type.orElseThrow(), true)}.${enumValue.value}<#else>${enumValue.value}</#if><#else>${enumValue.value}</#if></#if><#if type.constantNames?has_content><#if type.type?has_content>, </#if><#list type.constan [...]
-</#sep></#list>;
+<@compress single_line=true>
+    <#list type.enumValues as enumValue>
+        ${enumValue.name}(
+            <#if type.type.isPresent()>
+                (${helper.getLanguageTypeNameForTypeReference(type.type.orElseThrow(), true)})
+                <#if type.type.orElseThrow().isNonSimpleTypeReference()>
+                    <#if type.type.orElseThrow().isEnumTypeReference()>
+                        ${helper.getLanguageTypeNameForTypeReference(type.type.orElseThrow(), true)}.${enumValue.value}
+                    <#else>
+                        ${enumValue.value}
+                    </#if>
+                <#else>
+                    ${enumValue.value}
+                </#if>
+            </#if>
+            <#if type.constantNames?has_content>
+                <#if type.type?has_content>, </#if>
+                <#list type.constantNames as constantName>
+                    <#if type.getConstantType(constantName).isNonSimpleTypeReference()>
+                        <#if helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElse(null)) == 'null'>
+                            null
+                        <#elseif type.getConstantType(constantName).isEnumTypeReference()>
+                            ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)}.${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}<#else>(${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)}) ${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}</#if><#else>(${helper.getLanguageTypeNameForTypeReference(type [...]
+                        </#if>
+                    <#sep>, </#sep>
+                </#list>
+            </#if>)
+        <#sep>, </#sep>
+    </#list>;
+</...@compress>
 
 <#if type.type.isPresent()>
     private static final Logger logger = LoggerFactory.getLogger(${type.name}.class);
diff --git a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
index 8e28069..6d3a1c0 100644
--- a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
@@ -123,7 +123,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 
     // Properties.
     <#list type.propertyFields as field>
-    protected final <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name};
+    protected final ${helper.getLanguageTypeNameForField(field)} ${field.name};
     </#list>
 </#if>
 <#if parserArguments?has_content>
@@ -141,14 +141,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
     <@compress single_line=true>
     public ${type.name}(
         <#list type.getAllPropertyFields() as field>
-            <#if field.loopType?? && field.type.isByteBased()>
-                byte[]
-            <#elseif field.loopType??>
-                List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}>
-            <#else>
-                ${helper.getLanguageTypeNameForField(field)}
-            </#if>
-            ${field.name}
+            ${helper.getLanguageTypeNameForField(field)} ${field.name}
             <#sep>, </#sep>
         </#list>
         <#if filteredParserArguments?has_content>
@@ -193,18 +186,18 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
     }
 
 <#list type.abstractFields as field>
-    public abstract <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> get${field.asNamedField().orElseThrow().name?cap_first}();
+    public abstract ${helper.getLanguageTypeNameForField(field)} get${field.asNamedField().orElseThrow().name?cap_first}();
 
 </#list>
 <#list type.propertyFields as field>
-    public <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> get${field.name?cap_first}() {
+    public ${helper.getLanguageTypeNameForField(field)} get${field.name?cap_first}() {
         return ${field.name};
     }
 
 </#list>
 <#list type.virtualFields as field>
     <#if !type.isDiscriminatorField(field.name)>
-    public <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> get${field.name?cap_first}() {
+    public ${helper.getLanguageTypeNameForField(field)} get${field.name?cap_first}() {
         <#if helper.getLanguageTypeNameForField(field) = 'String'>
         return ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)});
         <#elseif helper.getLanguageTypeNameForField(field) = 'BigInteger'>
@@ -241,10 +234,10 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
                         // Array Field (${arrayField.name})
-                        <#if arrayField.type.isByteBased()>
+                        <#if arrayField.type.elementTypeReference.isByteBased()>
                         writeByteArrayField("${namedField.name}", ${namedField.name}, writeByteArray(writeBuffer, 8));
-                        <#elseif arrayField.type.isSimpleTypeReference()>
-                        writeSimpleTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});
+                        <#elseif arrayField.type.elementTypeReference.isSimpleTypeReference()>
+                        writeSimpleTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getDataWriterCall(arrayField.type.elementTypeReference, namedField.name)});
                         <#else>
                         writeComplexTypeArrayField("${namedField.name}", ${namedField.name}, writeBuffer);
                         </#if>
@@ -297,7 +290,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
                         // Manual Array Field (${manualArrayField.name})
-                        writeManualArrayField("${namedField.name}", ${namedField.name}, (${helper.getNonPrimitiveLanguageTypeNameForField(typedField)} _value) -> ${helper.toParseExpression(manualArrayField, manualArrayField.type, manualArrayField.serializeExpression, parserArguments)}, writeBuffer);
+                        writeManualArrayField("${namedField.name}", ${namedField.name}, (${helper.getNonPrimitiveLanguageTypeNameForField(typedField)} _value) -> ${helper.toParseExpression(manualArrayField, manualArrayField.type.elementTypeReference, manualArrayField.serializeExpression, parserArguments)}, writeBuffer);
                         <#break>
                     <#case "manual">
                         <#assign manualField = field.asManualField().orElseThrow()>
@@ -384,16 +377,17 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 <#switch field.typeName>
     <#case "array">
         <#assign arrayField = field.asArrayField().orElseThrow()>
+        <#assign arrayElementTypeReference = arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
         // Array field
         if(${arrayField.name} != null) {
-        <#if arrayField.type.isSimpleTypeReference()>
-            <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
-            lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.<#if arrayField.type.isByteBased()>length<#else>size()</#if>;
+        <#if arrayElementTypeReference.isSimpleTypeReference()>
+            <#assign simpleTypeReference = arrayElementTypeReference.asSimpleTypeReference().orElseThrow()>
+            lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.<#if arrayElementTypeReference.isByteBased()>length<#else>size()</#if>;
         <#elseif arrayField.isCountArrayField()>
             int i=0;
-            <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
-            for(${complexTypeReference.name} element : ${arrayField.name}) {
+            <#assign nonSimpleTypeReference = arrayElementTypeReference.asNonSimpleTypeReference().orElseThrow()>
+            for(${nonSimpleTypeReference.name} element : ${arrayField.name}) {
                 boolean last = ++i >= ${arrayField.name}.size();
                 lengthInBits += element.getLengthInBits();
             }
@@ -457,6 +451,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         <#break>
     <#case "manualArray">
         <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
+        <#assign arrayElementTypeReference = manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
         // Manual Array Field (${manualArrayField.name})
         lengthInBits += ${helper.toParseExpression(manualArrayField, helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 8;
@@ -587,8 +582,9 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign arrayField = field.asArrayField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
+                <#assign arrayElementTypeReference = arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
-                <#if typedField.type.isByteBased()>
+                <#if arrayElementTypeReference.isByteBased()>
                     <#if !field.isCountArrayField() && !field.isLengthArrayField()>
                         throw new ParseException("array fields of type byte only support 'count' and 'length' loop-types.");
                     </#if>
@@ -596,15 +592,15 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#else>
                 <#-- If this is a count array, we can directly initialize an array with the given size -->
                     <#if field.isCountArrayField()>
-                        List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = readCountArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+                        ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = readCountArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
                     <#-- In all other cases do we have to work with a list, that is later converted to an array -->
                     <#else>
                     <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
                         <#if field.isLengthArrayField()>
-                            List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = readLengthArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+                            ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = readLengthArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
                         <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
                         <#elseif field.isTerminatedArrayField()>
-                            List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = readTerminatedArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)});
+                            ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = readTerminatedArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)});
                         </#if>
                     </#if>
                 </#if>
@@ -655,11 +651,12 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
+                <#assign arrayElementTypeReference = manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
-                <#if manualArrayField.type.isByteBased()>
+                <#if arrayElementTypeReference.isByteBased()>
                     byte[] ${namedField.name} = readManualByteArrayField("${namedField.name}", readBuffer, (byte[] _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForField(manualArrayField)}) (${helper.toParseExpression(manualArrayField, manualArrayField.type, manualArrayField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserAr [...]
                 <#else>
-                    List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> ${namedField.name} = readManualArrayField("${namedField.name}", readBuffer, (List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForField(manualArrayField)}) (${helper.toParseExpression(manualAr [...]
+                    ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} ${namedField.name} = readManualArrayField("${namedField.name}", readBuffer, (${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForField(manualArrayField)}) (${helper.toParseExpression(manualArrayField, ma [...]
                 </#if>
                 <#break>
             <#case "manual">
@@ -778,7 +775,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 
     <#if type.isDiscriminatedParentTypeDefinition()>
         public static interface ${type.name}Builder {
-            ${type.name} build(<#list type.propertyFields as field><#if field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list><#if filteredParserArguments?has_content><#if type.propertyFields?has_content>, </#if><#list filteredParserArguments as arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, </#sep></#list></#if>);
+            ${type.name} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, </#sep></#list><#if filteredParserArguments?has_content><#if type.propertyFields?has_content>, </#if><#list filteredParserArguments as arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, </#sep></#list></#if>);
         }
 
     </#if>
@@ -786,7 +783,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         public static class ${type.name}Builder implements ${type.parentType.orElseThrow().name}.${type.parentType.orElseThrow().name}Builder {
         <#if type.propertyFields?has_content>
             <#list type.propertyFields as field>
-                private final <#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name};
+                private final ${helper.getLanguageTypeNameForField(field)} ${field.name};
             </#list>
         </#if>
         <#if filteredParserArguments?has_content>
@@ -795,7 +792,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
             </#list>
         </#if>
 
-        public ${type.name}Builder(<#list type.propertyFields as field><#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list><#if filteredParserArguments?has_content><#if type.propertyFields?has_content>, </#if><#list filteredParserArguments as arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${a [...]
+        public ${type.name}Builder(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, </#sep></#list><#if filteredParserArguments?has_content><#if type.propertyFields?has_content>, </#if><#list filteredParserArguments as arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, </#sep></#list></#if>) {
         <#list type.propertyFields as field>
             this.${field.name} = ${field.name};
         </#list>
@@ -806,7 +803,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         </#if>
         }
 
-        public ${type.name} build(<#list type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields as field><#if field.loopType?? && field.type.isByteBased()>byte[]<#elseif field.loopType??>List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}><#else>${helper.getLanguageTypeNameForField(field)}</#if> ${field.name}<#sep>, </#sep></#list><#if filteredParentParserArguments?has_content><#if type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow [...]
+        public ${type.name} build(<#list type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields as field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, </#sep></#list><#if filteredParentParserArguments?has_content><#if type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields?has_content>, </#if><#list filteredParentParserArguments as arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>,  [...]
             return new ${type.name}(<#list type.allPropertyFields as field>${field.name}<#sep>, </#sep></#list><#if filteredParserArguments?has_content><#if type.allPropertyFields?has_content>, </#if><#list filteredParserArguments as arg>${arg.name}<#sep>, </#sep></#list></#if>);
         }
     }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java
index 8468f82..36a615d 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java
@@ -19,6 +19,8 @@
 package org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields;
 
 import org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField;
+import org.apache.plc4x.plugins.codegenerator.types.references.ArrayTypeReference;
+import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
 import java.util.Map;
@@ -44,6 +46,19 @@ public class DefaultArrayField extends DefaultTypedNamedField implements ArrayFi
     }
 
     @Override
+    public void setType(TypeReference typeReference) {
+        if(!(typeReference instanceof ArrayTypeReference)) {
+            throw new IllegalArgumentException("Array fields can only have ArrayTypeReferences");
+        }
+        super.setType(typeReference);
+    }
+
+    @Override
+    public ArrayTypeReference getType() {
+        return (ArrayTypeReference) super.getType();
+    }
+
+    @Override
     public String toString() {
         return "DefaultArrayField{" +
             "loopType=" + loopType +
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java
index 9678161..60de76e 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java
@@ -19,6 +19,8 @@
 package org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields;
 
 import org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField;
+import org.apache.plc4x.plugins.codegenerator.types.references.ArrayTypeReference;
+import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
 import java.util.Map;
@@ -62,6 +64,19 @@ public class DefaultManualArrayField extends DefaultTypedNamedField implements M
     }
 
     @Override
+    public void setType(TypeReference typeReference) {
+        if(!(typeReference instanceof ArrayTypeReference)) {
+            throw new IllegalArgumentException("Manual array fields can only have ArrayTypeReferences");
+        }
+        super.setType(typeReference);
+    }
+
+    @Override
+    public ArrayTypeReference getType() {
+        return (ArrayTypeReference) super.getType();
+    }
+
+    @Override
     public String toString() {
         return "DefaultManualArrayField{" +
             "loopType=" + loopType +
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/references/DefaultArrayTypeReference.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/references/DefaultArrayTypeReference.java
new file mode 100644
index 0000000..c639e2b
--- /dev/null
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/references/DefaultArrayTypeReference.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.plugins.codegenerator.language.mspec.model.references;
+
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+import org.apache.plc4x.plugins.codegenerator.types.references.ArrayTypeReference;
+import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
+
+public class DefaultArrayTypeReference implements ArrayTypeReference {
+
+    final TypeReference elementTypeReference;
+
+    public DefaultArrayTypeReference(TypeReference elementTypeReference) {
+        this.elementTypeReference = elementTypeReference;
+    }
+
+    @Override
+    public TypeReference getElementTypeReference() {
+        return elementTypeReference;
+    }
+
+}
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
index b7bdafc..177add9 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
@@ -212,7 +212,7 @@ public class MessageFormatListener extends MSpecBaseListener implements LazyType
                 LOGGER.error("Error setting type for {}", field, throwable);
                 return;
             }
-            field.setType(typeReference);
+            field.setType(new DefaultArrayTypeReference(typeReference));
         });
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -330,7 +330,7 @@ public class MessageFormatListener extends MSpecBaseListener implements LazyType
                 LOGGER.error("Error setting type for {}", field, throwable);
                 return;
             }
-            field.setType(typeReference);
+            field.setType(new DefaultArrayTypeReference(typeReference));
         });
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -500,11 +500,11 @@ public class MessageFormatListener extends MSpecBaseListener implements LazyType
 
         List<Argument> parserArguments = new LinkedList<>();
         // For DataIO types, add all the arguments from the parent type.
-        if (!(ctx.parent.parent.parent.parent instanceof MSpecParser.ComplexTypeContext)
+/*        if (!(ctx.parent.parent.parent.parent instanceof MSpecParser.ComplexTypeContext)
             && ((MSpecParser.ComplexTypeContext) ctx.parent.parent.parent).params != null) {
             parserArguments.addAll(getParserArguments(
                 ((MSpecParser.ComplexTypeContext) ctx.parent.parent.parent).params.argument()));
-        }
+        }*/
         // Add all eventually existing local arguments.
         if (ctx.argumentList() != null) {
             parserArguments.addAll(getParserArguments(ctx.argumentList().argument()));
@@ -521,7 +521,11 @@ public class MessageFormatListener extends MSpecBaseListener implements LazyType
         DefaultDiscriminatedComplexTypeDefinition type =
             new DefaultDiscriminatedComplexTypeDefinition(typeName, attributes, parserArguments,
                 discriminatorValues, parserContexts.pop());
-        dispatchType(typeName, type);
+
+        // For DataIO we don't need to generate the sub-types as these will be PlcValues.
+        if(!(ctx.parent.parent instanceof MSpecParser.DataIoDefinitionContext)) {
+            dispatchType(typeName, type);
+        }
 
         // Add the type to the switch field definition.
         DefaultSwitchField switchField = getSwitchField();
diff --git a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
index ec3e21f..308f14a 100644
--- a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
+++ b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
@@ -141,10 +141,10 @@
 ]
 
 [type ArrayTypeTest
-    [array bit bitField count      '5']
-    [array int 8 intField count      '5']
-    [array uint 8 uintField count      '5']
-    [array float 32 floatField count      '5']
+    [array bit bitField count              '5']
+    [array int 8 intField count            '5']
+    [array uint 8 uintField count          '5']
+    [array float 32 floatField count       '5']
     [array float 64 doubleField count      '5']
     [array string 8 stringField count      '5']
 ]
diff --git a/pom.xml b/pom.xml
index 75760bc..b509f78 100644
--- a/pom.xml
+++ b/pom.xml
@@ -165,7 +165,7 @@
     <asciidoctorj.diagram.version>2.1.2</asciidoctorj.diagram.version>
 
     <skip-code-generation-tests>false</skip-code-generation-tests>
-    <skip-dependency-cve-scan>false</skip-dependency-cve-scan>
+    <skip-dependency-cve-scan>true</skip-dependency-cve-scan>
   </properties>
 
   <modules>