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

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 084e3f95009300db1fc635148d55168c8c96c697
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Tue Apr 2 19:32:07 2024 +0200

    Lazily create builders during transformations
---
 src/mdo/transformer.vm | 84 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 57 insertions(+), 27 deletions(-)

diff --git a/src/mdo/transformer.vm b/src/mdo/transformer.vm
index ac6cd05f0b..04b6b707b8 100644
--- a/src/mdo/transformer.vm
+++ b/src/mdo/transformer.vm
@@ -41,6 +41,7 @@ import java.util.Properties;
 import java.util.Objects;
 import java.util.function.BinaryOperator;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import org.apache.maven.api.annotations.Generated;
@@ -82,21 +83,25 @@ public class ${className} {
         if (target == null) {
             return null;
         }
-        ${class.name}.Builder builder = ${class.name}.newBuilder(target);
+        Supplier<${class.name}.Builder> creator = () -> 
${class.name}.newBuilder(target);
+        ${class.name}.Builder builder = null;
     #foreach ( $field in $allFields )
-        
transform${field.modelClass.name}_${Helper.capitalise($field.name)}(builder, 
target);
+        builder = (${class.name}.Builder) 
transform${field.modelClass.name}_${Helper.capitalise($field.name)}(creator, 
builder, target);
     #end
-        return builder.build();
+        return builder != null ? builder.build() : target;
     }
 
     #foreach ( $field in $allFields )
       #set ( $capField = ${Helper.capitalise($field.name)} )
-    protected void transform${class.name}_${capField}(${class.name}.Builder 
builder, ${class.name} target) {
+    protected ${class.name}.Builder 
transform${class.name}_${capField}(Supplier<? extends ${class.name}.Builder> 
creator, ${class.name}.Builder builder, ${class.name} target) {
       #if ( $field.type == "String" )
-        String newVal = transform(target.get${capField}());
-        builder.${field.name}(newVal != target.get${capField}() ? newVal : 
null);
+        String oldVal = target.get${capField}();
+        String newVal = transform(oldVal);
+        return newVal != oldVal ? (builder != null ? builder : 
creator.get()).${field.name}(newVal) : builder;
       #elseif ( $field.type == "java.util.List" && $field.to == "String" && 
$field.multiplicity == "*" )
-        builder.${field.name}(transform(target.get${capField}(), 
this::transform));
+        List<String> oldVal = target.get${capField}();
+        List<String> newVal = transform(oldVal, this::transform);
+        return newVal != oldVal ? (builder != null ? builder : 
creator.get()).${field.name}(newVal) : builder;
       #elseif ( $field.type == "java.util.Properties" && $field.to == "String" 
&& $field.multiplicity == "*" )
         Map<String, String> props = target.get${capField}();
         Map<String, String> newProps = null;
@@ -106,21 +111,28 @@ public class ${className} {
                 if (newProps == null) {
                     newProps = new HashMap<>();
                     newProps.putAll(props);
+                    builder = builder != null ? builder : creator.get();
                     builder.${field.name}(newProps);
                 }
                 newProps.put(entry.getKey(), newVal);
             }
         }
+        return builder;
       #elseif ( $field.to && $field.multiplicity == "1" )
-        ${field.to} newVal = transform${field.to}(target.get${capField}());
-        builder.${field.name}(newVal != target.get${capField}() ? newVal : 
null);
+        ${field.to} oldVal = target.get${capField}();
+        ${field.to} newVal = transform${field.to}(oldVal);
+        return newVal != oldVal ? (builder != null ? builder : 
creator.get()).${field.name}(newVal) : builder;
       #elseif ( $field.to && $field.multiplicity == "*" )
-        builder.${field.name}(transform(target.get${capField}(), 
this::transform${field.to}));
+        List<${field.to}> oldVal = target.get${capField}();
+        List<${field.to}> newVal = transform(oldVal, 
this::transform${field.to});
+        return newVal != oldVal ? (builder != null ? builder : 
creator.get()).${field.name}(newVal) : builder;
       #elseif ( $field.type == "DOM" )
-        XmlNode newVal = transform(target.get${capField}());
-        builder.${field.name}(newVal != target.get${capField}() ? newVal : 
null);
+        XmlNode oldVal = target.get${capField}();
+        XmlNode newVal = transform(oldVal);
+        return newVal != oldVal ? (builder != null ? builder : 
creator.get()).${field.name}(newVal) : builder;
       #elseif ( $field.type == "boolean" || $field.type == "int" || 
$field.type == "java.nio.file.Path" )
         // nothing to do, the transformer only handles strings
+        return builder;
       #else
         // TODO: type=${field.type} to=${field.to} 
multiplicity=${field.multiplicity}
       #end
@@ -130,11 +142,12 @@ public class ${className} {
   #end
 #end
     protected <T> List<T> transform(List<T> list, Function<T, T> transformer) {
-        List<T> newList = null;
+        List<T> newList = list;
         for (int i = 0; i < list.size(); i++) {
-            T newVal = transformer.apply(list.get(i));
-            if (newVal != list.get(i)) {
-                if (newList == null) {
+            T oldVal = list.get(i);
+            T newVal = transformer.apply(oldVal);
+            if (newVal != oldVal) {
+                if (newList == list) {
                     newList = new ArrayList<>(list);
                 }
                 newList.set(i, newVal);
@@ -143,17 +156,34 @@ public class ${className} {
         return newList;
     }
 
+    protected <T> Map<String, T> transform(Map<String, T> map, Function<T, T> 
transformer) {
+        Map<String, T> newMap = map;
+        for (String key : map.keySet()) {
+            T oldVal = map.get(key);
+            T newVal = transformer.apply(oldVal);
+            if (newVal != oldVal) {
+                if (newMap == map) {
+                    newMap = new HashMap<>(map);
+                }
+                newMap.put(key, newVal);
+            }
+        }
+        return newMap;
+    }
+
     protected XmlNode transform(XmlNode node) {
-        return node != null ? new XmlNodeImpl(
-                node.getPrefix(),
-                node.getNamespaceUri(),
-                node.getName(),
-                transform(node.getValue()),
-                node.getAttributes().entrySet()
-                        .stream().collect(Collectors.toMap(e -> e.getKey(), e 
-> transform(e.getValue()))),
-                node.getChildren().stream()
-                        .map(this::transform).collect(Collectors.toList()),
-                node.getInputLocation()
-        ) : null;
+        if (node != null) {
+            String oldValue = node.getValue();
+            String newValue = transform(oldValue);
+            Map<String, String> oldAttrs = node.getAttributes();
+            Map<String, String> newAttrs = transform(oldAttrs, 
this::transform);
+            List<XmlNode> oldChildren = node.getChildren();
+            List<XmlNode> newChildren = transform(oldChildren, 
this::transform);
+            if (oldValue != newValue || oldAttrs != newAttrs || oldChildren != 
newChildren) {
+                return new XmlNodeImpl(node.getPrefix(), 
node.getNamespaceUri(), node.getName(),
+                        newValue, newAttrs, newChildren, 
node.getInputLocation());
+            }
+        }
+        return node;
     }
 }

Reply via email to