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

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit b3a979a996b1c7893976d941fe94279ef3d8770f
Author: Volkan Yazici <[email protected]>
AuthorDate: Mon Feb 7 10:53:48 2022 +0100

    LOG4J2-3393 Refactor JTL TemplateResolvers into smaller components.
---
 .../template/json/resolver/TemplateResolvers.java  | 224 +++++++++++++++------
 1 file changed, 160 insertions(+), 64 deletions(-)

diff --git 
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
 
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
index 20ad802..450b874 100644
--- 
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
+++ 
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * Main class for compiling {@link TemplateResolver}s from a template.
@@ -192,6 +193,28 @@ public final class TemplateResolvers {
             return ofResolver(context, map);
         }
 
+        // Collect field resolver contexts.
+        List<FieldResolverContext<V>> fieldResolverContexts =
+                populateFieldResolverMethods(context, map);
+
+        // Short-circuit if the object is empty.
+        final int fieldCount = fieldResolverContexts.size();
+        if (fieldCount == 0) {
+            @SuppressWarnings("unchecked")
+            final TemplateResolver<V> emptyObjectResolver =
+                    (TemplateResolver<V>) EMPTY_OBJECT_RESOLVER;
+            return emptyObjectResolver;
+        }
+
+        // Create the resolver.
+        return new MapResolver<>(fieldResolverContexts);
+
+    }
+
+    private static <V, C extends TemplateResolverContext<V, C>> 
List<FieldResolverContext<V>> populateFieldResolverMethods(
+            final C context,
+            final Map<String, Object> map) {
+
         // Create resolver for each object field.
         final List<String> fieldNames = new ArrayList<>();
         final List<TemplateResolver<V>> fieldResolvers = new ArrayList<>();
@@ -204,15 +227,6 @@ public final class TemplateResolvers {
             }
         });
 
-        // Short-circuit if the object is empty.
-        final int fieldCount = fieldNames.size();
-        if (fieldCount == 0) {
-            @SuppressWarnings("unchecked")
-            final TemplateResolver<V> emptyObjectResolver =
-                    (TemplateResolver<V>) EMPTY_OBJECT_RESOLVER;
-            return emptyObjectResolver;
-        }
-
         // Prepare field names to avoid escape and truncation costs at runtime.
         final List<String> fieldPrefixes = fieldNames
                 .stream()
@@ -225,70 +239,152 @@ public final class TemplateResolvers {
                 })
                 .collect(Collectors.toList());
 
-        return new TemplateResolver<V>() {
-
-            @Override
-            public boolean isResolvable() {
-                // We have already excluded unresolvable ones while collecting
-                // the resolvers. Hence it is safe to return true here.
-                return true;
-            }
-
-            /**
-             * The parent resolver checking if each child is resolvable given
-             * the passed {@code value}.
-             *
-             * This is an optimization to skip the rendering of a parent if all
-             * its children are not resolvable given the passed {@code value}.
-             */
-            @Override
-            public boolean isResolvable(final V value) {
-                for (int fieldIndex = 0; fieldIndex < fieldCount; 
fieldIndex++) {
-                    final TemplateResolver<V> fieldResolver = 
fieldResolvers.get(fieldIndex);
-                    final boolean resolvable = 
fieldResolver.isResolvable(value);
-                    if (resolvable) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            /**
-             * The parent resolver combining all child resolver executions.
-              */
-            @Override
-            public void resolve(final V value, final JsonWriter jsonWriter) {
-                final StringBuilder jsonWriterStringBuilder = 
jsonWriter.getStringBuilder();
-                jsonWriter.writeObjectStart();
-                for (int resolvedFieldCount = 0, fieldIndex = 0; fieldIndex < 
fieldCount; fieldIndex++) {
+        // Collect field resolver contexts.
+        final int fieldCount = fieldNames.size();
+        return IntStream
+                .range(0, fieldCount)
+                .mapToObj(fieldIndex -> {
                     final TemplateResolver<V> fieldResolver = 
fieldResolvers.get(fieldIndex);
-                    final boolean resolvable = 
fieldResolver.isResolvable(value);
-                    if (!resolvable) {
-                        continue;
-                    }
-                    final boolean succeedingEntry = resolvedFieldCount > 0;
+                    final FieldResolverMethod<V> fieldResolverMethod;
                     final boolean flattening = fieldResolver.isFlattening();
                     if (flattening) {
-                        final int initLength = 
jsonWriterStringBuilder.length();
-                        fieldResolver.resolve(value, jsonWriter, 
succeedingEntry);
-                        final boolean resolved = 
jsonWriterStringBuilder.length() > initLength;
-                        if (resolved) {
-                            resolvedFieldCount++;
-                        }
+                        fieldResolverMethod = new 
FlatteningFieldResolverMethod<>(fieldResolver);
                     } else {
-                        if (succeedingEntry) {
-                            jsonWriter.writeSeparator();
-                        }
                         final String fieldPrefix = 
fieldPrefixes.get(fieldIndex);
-                        jsonWriter.writeRawString(fieldPrefix);
-                        fieldResolver.resolve(value, jsonWriter, 
succeedingEntry);
-                        resolvedFieldCount++;
+                        fieldResolverMethod = new 
PrefixedFieldResolverMethod<>(fieldPrefix, fieldResolver);
                     }
+                    return new FieldResolverContext<>(fieldResolver, 
fieldResolverMethod);
+                })
+                .collect(Collectors.toList());
+
+    }
+
+    private static final class FieldResolverContext<V> {
+
+        private final TemplateResolver<V> resolver;
+
+        private final FieldResolverMethod<V> resolverMethod;
+
+        private FieldResolverContext(final TemplateResolver<V> resolver, final 
FieldResolverMethod<V> resolverMethod) {
+            this.resolver = resolver;
+            this.resolverMethod = resolverMethod;
+        }
+
+    }
+
+    @FunctionalInterface
+    private interface FieldResolverMethod<V> {
+
+        boolean resolve(V value, JsonWriter jsonWriter, boolean 
succeedingEntry);
+
+    }
+
+    private static final class FlatteningFieldResolverMethod<V> implements 
FieldResolverMethod<V> {
+
+        private final TemplateResolver<V> fieldResolver;
+
+        private FlatteningFieldResolverMethod(final TemplateResolver<V> 
fieldResolver) {
+            this.fieldResolver = fieldResolver;
+        }
+
+        @Override
+        public boolean resolve(final V value, final JsonWriter jsonWriter, 
final boolean succeedingEntry) {
+            final boolean resolvable = fieldResolver.isResolvable(value);
+            if (!resolvable) {
+                return false;
+            }
+            final StringBuilder jsonWriterStringBuilder = 
jsonWriter.getStringBuilder();
+            final int initLength = jsonWriterStringBuilder.length();
+            fieldResolver.resolve(value, jsonWriter, succeedingEntry);
+            return jsonWriterStringBuilder.length() > initLength;
+        }
+
+    }
+
+    private static final class PrefixedFieldResolverMethod<V> implements 
FieldResolverMethod<V> {
+
+        private final String fieldPrefix;
+
+        private final TemplateResolver<V> fieldResolver;
+
+        private PrefixedFieldResolverMethod(final String fieldPrefix, final 
TemplateResolver<V> fieldResolver) {
+            this.fieldPrefix = fieldPrefix;
+            this.fieldResolver = fieldResolver;
+        }
+
+        @Override
+        public boolean resolve(final V value, final JsonWriter jsonWriter, 
final boolean succeedingEntry) {
+            final boolean resolvable = fieldResolver.isResolvable(value);
+            if (!resolvable) {
+                return false;
+            }
+            if (succeedingEntry) {
+                jsonWriter.writeSeparator();
+            }
+            jsonWriter.writeRawString(fieldPrefix);
+            fieldResolver.resolve(value, jsonWriter, succeedingEntry);
+            return true;
+        }
+
+    }
+
+    private static final class MapResolver<V> implements TemplateResolver<V> {
+
+        private final List<FieldResolverContext<V>> fieldResolverContexts;
+
+        private MapResolver(final List<FieldResolverContext<V>> 
fieldResolverContexts) {
+            this.fieldResolverContexts = fieldResolverContexts;
+        }
+
+        @Override
+        public boolean isResolvable() {
+            // We have already excluded unresolvable ones while collecting
+            // the resolvers; it is safe to return true here.
+            return true;
+        }
+
+        /**
+         * The parent resolver checking if each child is resolvable given
+         * the passed {@code value}.
+         *
+         * This is an optimization to skip the rendering of a parent if all
+         * its children are not resolvable for the given {@code value}.
+         */
+        @Override
+        public boolean isResolvable(final V value) {
+            int fieldCount = fieldResolverContexts.size();
+            // noinspection ForLoopReplaceableByForEach (avoid iterator 
instantiation)
+            for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
+                final TemplateResolver<V> fieldResolver = 
fieldResolverContexts.get(fieldIndex).resolver;
+                final boolean resolvable = fieldResolver.isResolvable(value);
+                if (resolvable) {
+                    return true;
                 }
-                jsonWriter.writeObjectEnd();
             }
+            return false;
+        }
 
-        };
+        /**
+         * The parent resolver combining all child resolver executions.
+         */
+        @Override
+        public void resolve(final V value, final JsonWriter jsonWriter) {
+            jsonWriter.writeObjectStart();
+            int fieldCount = fieldResolverContexts.size();
+            for (int resolvedFieldCount = 0, fieldIndex = 0; fieldIndex < 
fieldCount; fieldIndex++) {
+                FieldResolverContext<V> fieldResolverContext = 
fieldResolverContexts.get(fieldIndex);
+                final boolean resolvable = 
fieldResolverContext.resolver.isResolvable(value);
+                if (!resolvable) {
+                    continue;
+                }
+                final boolean succeedingEntry = resolvedFieldCount > 0;
+                final boolean resolved = 
fieldResolverContext.resolverMethod.resolve(value, jsonWriter, succeedingEntry);
+                if (resolved) {
+                    resolvedFieldCount++;
+                }
+            }
+            jsonWriter.writeObjectEnd();
+        }
 
     }
 

Reply via email to