You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/09/24 19:13:28 UTC

[plc4x] 01/04: fix: fix stackoverflow on type referencing each other

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

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

commit 9470bbb3d6b06da665e3db7fe0e25c8f04e516db
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Sep 24 20:30:54 2021 +0200

    fix: fix stackoverflow on type referencing each other
---
 .../BaseFreemarkerLanguageTemplateHelper.java      | 71 +++++++++++++---------
 1 file changed, 42 insertions(+), 29 deletions(-)

diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
index 286da39..e494acd 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
@@ -23,12 +23,8 @@ import net.objecthunter.exp4j.ExpressionBuilder;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
 import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
 import org.apache.plc4x.plugins.codegenerator.types.fields.*;
-import org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference;
-import org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference;
-import org.apache.plc4x.plugins.codegenerator.types.references.StringTypeReference;
-import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
+import org.apache.plc4x.plugins.codegenerator.types.references.*;
 import org.apache.plc4x.plugins.codegenerator.types.terms.*;
-import org.w3c.dom.Node;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -199,13 +195,18 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * @return collection of complex type references used in the type.
      */
     public Collection<String> getComplexTypeReferences(TypeDefinition baseType) {
-        Set<String> complexTypeReferences = new HashSet<>();
+        return getComplexTypeReferences(baseType, new HashSet<>());
+    }
+
+    public Collection<String> getComplexTypeReferences(TypeDefinition baseType, Set<String> complexTypeReferences) {
+        // We add ourselves to avoid a stackoverflow
+        complexTypeReferences.add(baseType.getName());
         // 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()).getName());
+                String typeReferenceName = ((ComplexTypeReference) discriminatedComplexTypeDefinition.getParentType().getTypeReference()).getName();
+                complexTypeReferences.add(typeReferenceName);
             }
         }
         // If it's a complex type definition, add all the types referenced by any property fields
@@ -222,13 +223,14 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
                 } else if (field instanceof SwitchField) {
                     SwitchField switchField = (SwitchField) field;
                     for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
-                        complexTypeReferences.addAll(getComplexTypeReferences(switchCase));
+                        if (complexTypeReferences.contains(switchCase.getName())) {
+                            continue;
+                        }
+                        complexTypeReferences.addAll(getComplexTypeReferences(switchCase, complexTypeReferences));
                     }
                 }
             }
-        }
-        // In case this is a enum type, we have to check all the constant types.
-        else if (baseType instanceof EnumTypeDefinition) {
+        } else if (baseType instanceof EnumTypeDefinition) {// In case this is an enum type, we have to check all the constant types.
             for (String constantName : ((EnumTypeDefinition) baseType).getConstantNames()) {
                 final TypeReference constantType = ((EnumTypeDefinition) thisType).getConstantType(constantName);
                 if (constantType instanceof ComplexTypeReference) {
@@ -246,6 +248,9 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
                 }
             }
         }
+
+        // We remove ourselves to avoid a stackoverflow
+        complexTypeReferences.remove(baseType.getName());
         return complexTypeReferences;
     }
 
@@ -323,13 +328,13 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         if (!(typeReference instanceof ComplexTypeReference)) {
             throw new FreemarkerException("type reference for enum types must be of type complex type");
         }
-        ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
-        final TypeDefinition typeDefinition = types.get(complexTypeReference.getName());
+        String typeName = ((ComplexTypeReference) typeReference).getName();
+        final TypeDefinition typeDefinition = types.get(typeName);
         if (typeDefinition == null) {
-            throw new FreemarkerException("Couldn't find given enum type definition with name " + complexTypeReference.getName());
+            throw new FreemarkerException("Couldn't find given enum type definition with name " + typeName);
         }
         if (!(typeDefinition instanceof EnumTypeDefinition)) {
-            throw new FreemarkerException("Referenced type with name " + complexTypeReference.getName() + " is not an enum type");
+            throw new FreemarkerException("Referenced type with name " + typeName + " is not an enum type");
         }
         EnumTypeDefinition enumTypeDefinition = (EnumTypeDefinition) typeDefinition;
         // Enum types always have simple type references.
@@ -368,7 +373,11 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         if (!(getThisTypeDefinition() instanceof ComplexTypeDefinition)) {
             return null;
         }
-        return ((ComplexTypeDefinition) getThisTypeDefinition()).getAllPropertyFields()
+        return getAllPropertyFields((ComplexTypeDefinition) getThisTypeDefinition(), fieldName);
+    }
+
+    public PropertyField getAllPropertyFields(ComplexTypeDefinition complexTypeDefinition, String fieldName) {
+        return complexTypeDefinition.getAllPropertyFields()
             .stream()
             .filter(propertyField -> propertyField.getName().equals(fieldName))
             .findFirst()
@@ -379,7 +388,11 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         if (!(getThisTypeDefinition() instanceof ComplexTypeDefinition)) {
             return null;
         }
-        return ((ComplexTypeDefinition) getThisTypeDefinition()).getPropertyFields()
+        return getPropertyField((ComplexTypeDefinition) getThisTypeDefinition(), fieldName);
+    }
+
+    public PropertyField getPropertyField(ComplexTypeDefinition complexTypeDefinition, String fieldName) {
+        return complexTypeDefinition.getPropertyFields()
             .stream()
             .filter(propertyField -> propertyField.getName().equals(fieldName))
             .findFirst()
@@ -696,8 +709,8 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * @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));
+        return ((ComplexTypeDefinition) thisType).getAllPropertyFields().stream()
+            .anyMatch(field -> !(field instanceof DiscriminatorField) && field.getName().equals(discriminatorName));
     }
 
     /**
@@ -711,8 +724,8 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     public boolean isDiscriminatorField(String discriminatorName) {
         List<String> names = getDiscriminatorNames();
         if (names != null) {
-            return getDiscriminatorNames().stream().anyMatch(
-                field -> field.equals(discriminatorName));
+            return getDiscriminatorNames().stream()
+                .anyMatch(field -> field.equals(discriminatorName));
         }
         return false;
     }
@@ -844,7 +857,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         }
         TypeDefinition complexTypeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
         if (complexTypeDefinition.getParserArguments().length <= index) {
-            throw new FreemarkerException("Type " + complexTypeReference.getName() + " specifies too few parser arguments");
+            throw new FreemarkerException("Type " + complexTypeReference.getName() + " specifies too few parser arguments. Available:" + complexTypeDefinition.getParserArguments().length + " index:" + index);
         }
         return complexTypeDefinition.getParserArguments()[index].getType();
     }
@@ -1001,16 +1014,16 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * Confirms if a variable is an virtual variable. These need to be handled differently when serializing and parsing.
      *
      * @param vl The variable to search for.
-     * @return boolean returns true if the variable's name is an vritual field
+     * @return boolean returns true if the variable's name is an virtual field
      */
     protected boolean isVariableLiteralVirtualField(VariableLiteral vl) {
-        List<Field> fields = null;
+        List<Field> fields = new ArrayList<>();
         if (thisType instanceof ComplexTypeDefinition) {
             ComplexTypeDefinition complexType = (ComplexTypeDefinition) getThisTypeDefinition();
-            fields = complexType.getFields();
-        }
-        if (fields == null) {
-            return false;
+            fields.addAll(complexType.getFields());
+            if (complexType.getParentType() != null) {
+                fields.addAll(((ComplexTypeDefinition) complexType.getParentType()).getFields());
+            }
         }
         for (Field field : fields) {
             if (field.getTypeName().equals(VIRTUAL)) {