From 0fe7e9282d44ae5ab12e64c636585ea3ad0c3c5f Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Mon, 5 Sep 2022 13:27:35 +0200
Subject: [PATCH] begin with default mappings using templates

- also indirectly work on #55 to include marshalling methods only when needed
---
 .../src/main/jastadd/Intermediate.jadd        |  4 ++
 .../src/main/jastadd/IntermediateToYAML.jrag  | 11 +++++
 .../src/main/jastadd/Mappings.jrag            | 24 ++++++++++-
 .../src/main/jastadd/Navigation.jrag          | 25 +++++++++++
 .../src/main/jastadd/RagConnect.relast        |  4 ++
 .../main/resources/mappingDefinition.mustache | 43 +++++++++++++++++++
 .../src/main/resources/ragconnect.mustache    |  4 +-
 7 files changed, 111 insertions(+), 4 deletions(-)

diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd
index 1a24fa9..036159f 100644
--- a/ragconnect.base/src/main/jastadd/Intermediate.jadd
+++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd
@@ -333,6 +333,10 @@ aspect MustacheRagConnect {
 
   // === MappingDefinition ===
   syn boolean MappingDefinition.isUsed() = !effectiveUsedAt().isEmpty();
+  eq SerializeListMapping.isUsed() = ragconnect().defaultListToBytesMapping().isUsed();
+  eq SerializeJavaUtilListMapping.isUsed() = ragconnect().defaultJavaUtilListToBytesMapping().isUsed();
+  eq DeserializeListMapping.isUsed() = program().typeDecls().stream().anyMatch(
+          typeDecl -> ragconnect().defaultBytesToListMapping(typeDecl.getName()).isUsed());
 
   // === attributes needed for computing above ones ===
   syn List<EndpointDefinition> RagConnect.givenEndpointDefinitionList() {
diff --git a/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag b/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag
index 49c2693..23f32d9 100644
--- a/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag
+++ b/ragconnect.base/src/main/jastadd/IntermediateToYAML.jrag
@@ -147,6 +147,17 @@ aspect IntermediateToYAML {
     return result;
   }
 
+  syn Element TemplateDefaultMappingDefinition.toYAML() {
+    MappingElement result = new MappingElement();
+
+    // ragconnect / mapping
+    result.put("isUsed" , isUsed());
+    result.put("isSerializeListMapping" , isSerializeListMapping());
+    result.put("isSerializeJavaUtilListMapping" , isSerializeJavaUtilListMapping());
+    result.put("isDeserializeListMapping" , isDeserializeListMapping());
+    return result;
+  }
+
   syn Element DependencyDefinition.toYAML() {
     MappingElement result = new MappingElement();
     // dependencyDefinition
diff --git a/ragconnect.base/src/main/jastadd/Mappings.jrag b/ragconnect.base/src/main/jastadd/Mappings.jrag
index e92fc4f..133fae2 100644
--- a/ragconnect.base/src/main/jastadd/Mappings.jrag
+++ b/ragconnect.base/src/main/jastadd/Mappings.jrag
@@ -27,6 +27,16 @@ aspect DefaultMappings {
     result.setContent(content);
     return result;
   }
+  private TemplateDefaultMappingDefinition RagConnect.initTemplateMappingDefinition(
+      TemplateDefaultMappingDefinition prototype, String id, String type, boolean fromBytes) {
+    MappingDefinitionType givenType = new JavaMappingDefinitionType().setType(new SimpleJavaTypeUse(type));
+    MappingDefinitionType bytesType = new JavaArrayMappingDefinitionType().setType(new SimpleJavaTypeUse("byte"));
+
+    prototype.setID(id);
+    prototype.setFromType(fromBytes ? bytesType : givenType);
+    prototype.setToType(fromBytes ? givenType : bytesType);
+    return prototype;
+  }
 
   private DefaultMappingDefinition RagConnect.baseDefaultMappingDefinition(String fromTypeName, String toTypeName, String content) {
     return createDefaultMappingDefinition("_Default", fromTypeName, toTypeName, content);
@@ -81,7 +91,7 @@ aspect DefaultMappings {
             "com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();\n" +
             "com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();\n" +
             "com.fasterxml.jackson.core.JsonParser parser = factory.createParser(content);\n" +
-            configJastAddList() + "<" + typeName + ">" + " result = " + typeName + ".deserializeList((com.fasterxml.jackson.databind.node.ArrayNode)mapper.readTree(parser));\n" +
+            configJastAddList() + "<" + typeName + ">" + " result = " + typeName + ".deserializeListOf" + typeName + "((com.fasterxml.jackson.databind.node.ArrayNode)mapper.readTree(parser));\n" +
             "parser.close();\n" +
             "return result;"
     );
@@ -155,6 +165,15 @@ aspect DefaultMappings {
       "char", "String", "return String.valueOf(input);");
 }
 
+aspect TemplateDefaultMappingDefinitions {
+  syn nta TemplateDefaultMappingDefinition RagConnect.serializeListMapping() = initTemplateMappingDefinition(
+          new SerializeListMapping(), "SerializeListMapping", "JastAddList", false);
+  syn nta TemplateDefaultMappingDefinition RagConnect.serializeJavaUtilListMapping() = initTemplateMappingDefinition(
+          new SerializeListMapping(), "SerializeJavaUtilListMapping", "java.util.List", false);
+  syn nta TemplateDefaultMappingDefinition RagConnect.deserializeListMapping(String name) = initTemplateMappingDefinition(
+          new DeserializeListMapping().setName(name), "DeserializeListMapping", "JastAddList", true);
+}
+
 aspect Mappings {
   // --- effectiveMappings ---
   syn java.util.List<MappingDefinition> EndpointDefinition.effectiveMappings() {
@@ -390,9 +409,12 @@ aspect Mappings {
       result.add(defaultBytesToTreeMapping(typeDecl.getName()));
       result.add(defaultTreeToBytesMapping(typeDecl.getName()));
       result.add(defaultBytesToListMapping(typeDecl.getName()));
+      result.add(deserializeListMapping(typeDecl.getName()));
     }
     result.add(defaultListToBytesMapping());
     result.add(defaultJavaUtilListToBytesMapping());
+    result.add(serializeListMapping());
+    result.add(serializeJavaUtilListMapping());
 //    // string conversion
 //    result.add(defaultStringToBooleanMapping());
 //    result.add(defaultStringToIntMapping());
diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag
index 5288a9f..02f6f23 100644
--- a/ragconnect.base/src/main/jastadd/Navigation.jrag
+++ b/ragconnect.base/src/main/jastadd/Navigation.jrag
@@ -36,6 +36,24 @@ aspect GeneratedNavigation {
   syn boolean EndpointTarget.isRelationEndpointTarget() = false;
   eq RelationEndpointTarget.isRelationEndpointTarget() = true;
 
+  /** Tests if TemplateDefaultMappingDefinition is a SerializeListMapping.
+  *  @return 'true' if this is a SerializeListMapping, otherwise 'false'
+  */
+  syn boolean TemplateDefaultMappingDefinition.isSerializeListMapping() = false;
+  eq SerializeListMapping.isSerializeListMapping() = true;
+
+  /** Tests if TemplateDefaultMappingDefinition is a SerializeJavaUtilListMapping.
+  *  @return 'true' if this is a SerializeJavaUtilListMapping, otherwise 'false'
+  */
+  syn boolean TemplateDefaultMappingDefinition.isSerializeJavaUtilListMapping() = false;
+  eq SerializeJavaUtilListMapping.isSerializeJavaUtilListMapping() = true;
+
+  /** Tests if TemplateDefaultMappingDefinition is a DeserializeListMapping.
+  *  @return 'true' if this is a DeserializeListMapping, otherwise 'false'
+  */
+  syn boolean TemplateDefaultMappingDefinition.isDeserializeListMapping() = false;
+  eq DeserializeListMapping.isDeserializeListMapping() = true;
+
   /** casts a EndpointTarget into a TokenEndpointTarget if possible.
    *  @return 'this' cast to a TokenEndpointTarget or 'null'
    */
@@ -80,6 +98,13 @@ aspect GeneratedNavigation {
 }
 aspect RagConnectNavigation {
 
+  // adapted from generated navigation, was defined only for DefaultMappingDefinition
+  /** Tests if MappingDefinition is a TemplateDefaultMappingDefinition.
+  *  @return 'true' if this is a TemplateDefaultMappingDefinition, otherwise 'false'
+  */
+  syn boolean MappingDefinition.isTemplateDefaultMappingDefinition() = false;
+  eq TemplateDefaultMappingDefinition.isTemplateDefaultMappingDefinition() = true;
+
   // --- program ---
   eq RagConnect.getChild().program() = getProgram();
 
diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast
index df50e3d..ef96abf 100644
--- a/ragconnect.base/src/main/jastadd/RagConnect.relast
+++ b/ragconnect.base/src/main/jastadd/RagConnect.relast
@@ -28,6 +28,10 @@ abstract MappingDefinitionType ::= ;
 JavaMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse;
 JavaArrayMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse;
 DefaultMappingDefinition : MappingDefinition;
+abstract TemplateDefaultMappingDefinition : DefaultMappingDefinition ;
+SerializeListMapping : TemplateDefaultMappingDefinition ;
+SerializeJavaUtilListMapping : TemplateDefaultMappingDefinition ;
+DeserializeListMapping : TemplateDefaultMappingDefinition ::= <Name> ;
 
 Handler ::= <ClassName> <UniqueName> <InUse:boolean>;
 
diff --git a/ragconnect.base/src/main/resources/mappingDefinition.mustache b/ragconnect.base/src/main/resources/mappingDefinition.mustache
index b6a035e..392f444 100644
--- a/ragconnect.base/src/main/resources/mappingDefinition.mustache
+++ b/ragconnect.base/src/main/resources/mappingDefinition.mustache
@@ -1,3 +1,46 @@
+{{#isUsed}}
+  {{#isTemplateDefaultMappingDefinition}}
+    {{#isSerializeListMapping}}
+public void {{configJastAddList}}.serialize(com.fasterxml.jackson.core.JsonGenerator g) throws SerializationException {
+  try {
+    g.writeStartArray();
+    for (T child : this) {
+      child.serialize(g);
+    }
+    g.writeEndArray();
+  } catch (java.io.IOException e) {
+    throw new SerializationException("unable to serialize {{configJastAddList}}", e);
+  }
+}
+    {{/isSerializeListMapping}}
+    {{#SerializeJavaUtilListMapping}}
+protected static <T extends ASTNode> void ASTNode.serializeJavaUtilList(
+        java.util.List<T> input, com.fasterxml.jackson.core.JsonGenerator g) throws SerializationException {
+  try {
+    g.writeStartArray();
+    for (T child : input) {
+      child.serialize(g);
+    }
+    g.writeEndArray();
+  } catch (java.io.IOException e) {
+    throw new SerializationException("unable to serialize list", e);
+  }
+}
+    {{/SerializeJavaUtilListMapping}}
+    {{#DeserializeListMapping}}
+public static {{configJastAddList}}<{{Name}}> {{Name}}.deserializeListOf{{Name}}(com.fasterxml.jackson.databind.node.ArrayNode node) throws DeserializationException {
+  {{configJastAddList}}<{{Name}}> result = new {{configJastAddList}}<>();
+  for (java.util.Iterator<com.fasterxml.jackson.databind.JsonNode> it = node.elements(); it.hasNext();) {
+    com.fasterxml.jackson.databind.JsonNode element = it.next();
+    result.add(deserialize(element));
+  }
+  return result;
+}
+    {{/DeserializeListMapping}}
+  {{/isTemplateDefaultMappingDefinition}}
+  {{^TemplateDefaultMappingDefinition}}
 protected {{{toType}}} ASTNode.{{methodName}}({{{fromType}}} {{FromVariableName}}) throws Exception {
   {{{Content}}}
 }
+  {{/TemplateDefaultMappingDefinition}}
+{{/isUsed}}
diff --git a/ragconnect.base/src/main/resources/ragconnect.mustache b/ragconnect.base/src/main/resources/ragconnect.mustache
index c428021..738ecbe 100644
--- a/ragconnect.base/src/main/resources/ragconnect.mustache
+++ b/ragconnect.base/src/main/resources/ragconnect.mustache
@@ -15,9 +15,7 @@ aspect RagConnect {
   }
 
   {{#allMappingDefinitions}}
-  {{#isUsed}}
   {{> mappingDefinition}}
-  {{/isUsed}}
   {{/allMappingDefinitions}}
 
   {{#allDependencyDefinitionList}}
@@ -65,7 +63,7 @@ aspect RagConnect {
     return this;
   }
 
-  {{> ListAspect}}
+{{!{{> ListAspect}}
 
   static void ASTNode.{{logConsoleOut}}(String message, Object... args) {
     System.out.println(String.format(message, args));
-- 
GitLab