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

exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new f3fed9f6d2 NIFI-14660 Git Flow normalization sorts Lists and Sets of 
of Strings and Enums (#10016)
f3fed9f6d2 is described below

commit f3fed9f6d20c4f625b868c9e62e81b86c1bdeb14
Author: Pierre Villard <pierre.villard...@gmail.com>
AuthorDate: Tue Jun 17 16:22:33 2025 +0200

    NIFI-14660 Git Flow normalization sorts Lists and Sets of of Strings and 
Enums (#10016)
    
    Signed-off-by: David Handermann <exceptionfact...@apache.org>
---
 .../serialize/JacksonFlowSnapshotSerializer.java   |  1 +
 .../git/serialize/SortedEnumSetSerializer.java     | 48 ++++++++++++++
 .../serialize/SortedStringCollectionsModule.java   | 60 +++++++++++++++++
 .../git/serialize/SortedStringListSerializer.java  | 75 ++++++++++++++++++++++
 .../git/serialize/SortedStringSetSerializer.java   | 46 +++++++++++++
 .../JacksonFlowSnapshotSerializerTest.java         | 17 +++++
 6 files changed, 247 insertions(+)

diff --git 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializer.java
 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializer.java
index 683e96b50c..b39aec95bf 100644
--- 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializer.java
+++ 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializer.java
@@ -43,6 +43,7 @@ public class JacksonFlowSnapshotSerializer implements 
FlowSnapshotSerializer {
             .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
             .enable(SerializationFeature.INDENT_OUTPUT)
             .addModule(new VersionedComponentModule())
+            .addModule(new SortedStringCollectionsModule())
             .build();
 
     @Override
diff --git 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedEnumSetSerializer.java
 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedEnumSetSerializer.java
new file mode 100644
index 0000000000..ed03030dcb
--- /dev/null
+++ 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedEnumSetSerializer.java
@@ -0,0 +1,48 @@
+/*
+ *  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.nifi.registry.flow.git.serialize;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+public class SortedEnumSetSerializer extends StdSerializer<Set<? extends 
Enum<?>>> {
+
+    public SortedEnumSetSerializer() {
+        super((Class<Set<? extends Enum<?>>>) (Class<?>) Set.class);
+    }
+
+    @Override
+    public void serialize(final Set<? extends Enum<?>> value, final 
JsonGenerator gen, final SerializerProvider provider) throws IOException {
+        final List<String> sorted = value.stream()
+                .map(Enum::name)
+                .sorted()
+                .toList();
+
+        gen.writeStartArray();
+        for (final String str : sorted) {
+            gen.writeString(str);
+        }
+        gen.writeEndArray();
+    }
+}
+
diff --git 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringCollectionsModule.java
 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringCollectionsModule.java
new file mode 100644
index 0000000000..215d7db1fe
--- /dev/null
+++ 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringCollectionsModule.java
@@ -0,0 +1,60 @@
+/*
+ *  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.nifi.registry.flow.git.serialize;
+
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializationConfig;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
+import com.fasterxml.jackson.databind.type.CollectionType;
+
+import java.util.List;
+import java.util.Set;
+
+public class SortedStringCollectionsModule extends SimpleModule {
+
+    final Set<String> fieldsToSkipSorting = 
Set.of("inheritedParameterContexts");
+
+    @Override
+    public void setupModule(final SetupContext context) {
+        super.setupModule(context);
+        context.addBeanSerializerModifier(new BeanSerializerModifier() {
+            @Override
+            public JsonSerializer<?> modifyCollectionSerializer(final 
SerializationConfig config,
+                    final CollectionType valueType,
+                    final BeanDescription beanDesc,
+                    final JsonSerializer<?> serializer) {
+                // Only apply to List<String>
+                if (List.class.isAssignableFrom(valueType.getRawClass()) && 
valueType.getContentType().getRawClass() == String.class) {
+                    return new 
SortedStringListSerializer((JsonSerializer<Object>) serializer, 
fieldsToSkipSorting);
+                }
+                // Only apply to Set<String>
+                if (Set.class.isAssignableFrom(valueType.getRawClass()) && 
valueType.getContentType().getRawClass() == String.class) {
+                    return new SortedStringSetSerializer();
+                }
+                // Only apply to set of enums
+                if (Set.class.isAssignableFrom(valueType.getRawClass()) && 
valueType.getContentType().isEnumType()) {
+                    return new SortedEnumSetSerializer();
+                }
+                return serializer;
+            }
+        });
+    }
+}
+
diff --git 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringListSerializer.java
 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringListSerializer.java
new file mode 100644
index 0000000000..348da9bb1b
--- /dev/null
+++ 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringListSerializer.java
@@ -0,0 +1,75 @@
+/*
+ *  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.nifi.registry.flow.git.serialize;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class SortedStringListSerializer extends StdSerializer<List<String>> 
implements ContextualSerializer {
+
+    private final JsonSerializer<Object> defaultSerializer;
+    private final Set<String> fieldsToSkipSorting;
+    private final String currentFieldName; // for ContextualSerializer
+
+    public SortedStringListSerializer(final JsonSerializer<Object> 
defaultSerializer, final Set<String> fieldsToSkipSorting) {
+        this(defaultSerializer, fieldsToSkipSorting, null);
+    }
+
+    public SortedStringListSerializer(final JsonSerializer<Object> 
defaultSerializer, final Set<String> fieldsToSkipSorting, final String 
currentFieldName) {
+        super((Class<List<String>>) (Class<?>) List.class);
+        this.defaultSerializer = defaultSerializer;
+        this.fieldsToSkipSorting = fieldsToSkipSorting;
+        this.currentFieldName = currentFieldName;
+    }
+
+    @Override
+    public void serialize(final List<String> value, final JsonGenerator gen, 
final SerializerProvider provider) throws IOException {
+        if (fieldsToSkipSorting.contains(currentFieldName)) {
+            // Skip sorting, delegate to default
+            defaultSerializer.serialize(value, gen, provider);
+            return;
+        }
+
+        final List<String> sorted = new ArrayList<>(value);
+        Collections.sort(sorted);
+
+        gen.writeStartArray();
+        for (final String str : sorted) {
+            gen.writeString(str);
+        }
+        gen.writeEndArray();
+    }
+
+    @Override
+    public JsonSerializer<?> createContextual(final SerializerProvider prov, 
final BeanProperty property) throws JsonMappingException {
+        final JsonSerializer<Object> defaultSer = 
prov.findValueSerializer(prov.constructType(List.class), property);
+        final String fieldName = property != null ? property.getName() : null;
+        return new SortedStringListSerializer(defaultSer, fieldsToSkipSorting, 
fieldName);
+    }
+}
diff --git 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringSetSerializer.java
 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringSetSerializer.java
new file mode 100644
index 0000000000..1593941122
--- /dev/null
+++ 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/serialize/SortedStringSetSerializer.java
@@ -0,0 +1,46 @@
+/*
+ *  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.nifi.registry.flow.git.serialize;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class SortedStringSetSerializer extends StdSerializer<Set<String>> {
+
+    public SortedStringSetSerializer() {
+        super((Class<Set<String>>) (Class<?>) Set.class);
+    }
+
+    @Override
+    public void serialize(final Set<String> value, final JsonGenerator gen, 
final SerializerProvider provider) throws IOException {
+        final List<String> sorted = new ArrayList<>(value);
+        Collections.sort(sorted);
+        gen.writeStartArray();
+        for (final String str : sorted) {
+            gen.writeString(str);
+        }
+        gen.writeEndArray();
+    }
+}
diff --git 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/test/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializerTest.java
 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/test/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializerTest.java
index 5553035be9..a0bd0370e8 100644
--- 
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/test/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializerTest.java
+++ 
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/test/java/org/apache/nifi/registry/flow/git/serialize/JacksonFlowSnapshotSerializerTest.java
@@ -23,10 +23,14 @@ import org.apache.nifi.flow.VersionedParameter;
 import org.apache.nifi.flow.VersionedParameterContext;
 import org.apache.nifi.flow.VersionedProcessGroup;
 import org.apache.nifi.flow.VersionedProcessor;
+import org.apache.nifi.flow.VersionedPropertyDescriptor;
+import org.apache.nifi.flow.VersionedResourceDefinition;
+import org.apache.nifi.flow.VersionedResourceType;
 import org.apache.nifi.registry.flow.RegisteredFlowSnapshot;
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -45,6 +49,7 @@ public class JacksonFlowSnapshotSerializerTest {
 
         final VersionedParameterContext versionedParameterContext = new 
VersionedParameterContext();
         versionedParameterContext.setIdentifier("myParamContext");
+        
versionedParameterContext.setInheritedParameterContexts(List.of("inheritedContext2",
 "inheritedContext3", "inheritedContext1"));
 
         VersionedParameter parameter1 = new VersionedParameter();
         parameter1.setName("name1");
@@ -55,8 +60,15 @@ public class JacksonFlowSnapshotSerializerTest {
 
         versionedParameterContext.setParameters(Set.of(parameter2, parameter1, 
parameter3));
 
+        final VersionedPropertyDescriptor descriptor = new 
VersionedPropertyDescriptor();
+        final VersionedResourceDefinition resourceDefinition = new 
VersionedResourceDefinition();
+        resourceDefinition.setResourceTypes(Set.of(VersionedResourceType.TEXT, 
VersionedResourceType.URL, VersionedResourceType.FILE));
+        descriptor.setResourceDefinition(resourceDefinition);
+
         final VersionedProcessor processor1 = new VersionedProcessor();
         processor1.setIdentifier("proc1");
+        processor1.setAutoTerminatedRelationships(Set.of("success", 
"failure"));
+        processor1.setPropertyDescriptors(Map.of("prop1", descriptor));
         final VersionedProcessor processor2 = new VersionedProcessor();
         processor2.setIdentifier("proc2");
         final VersionedProcessor processor3 = new VersionedProcessor();
@@ -82,10 +94,15 @@ public class JacksonFlowSnapshotSerializerTest {
 
         assertEquals(3, processors.size());
         assertEquals("proc1", processors.get(0).get("identifier").asText());
+        assertEquals("[ \"failure\", \"success\" ]", 
processors.get(0).get("autoTerminatedRelationships").toPrettyString());
+        assertEquals("[ \"FILE\", \"TEXT\", \"URL\" ]", 
processors.get(0).get("propertyDescriptors").get("prop1").get("resourceDefinition").get("resourceTypes").toPrettyString());
+
         assertEquals("proc2", processors.get(1).get("identifier").asText());
         assertEquals("proc3", processors.get(2).get("identifier").asText());
 
         assertEquals(1, parameterContexts.size());
+        assertEquals("[ \"inheritedContext2\", \"inheritedContext3\", 
\"inheritedContext1\" ]", 
parameterContext.get("inheritedParameterContexts").toPrettyString());
+
         assertEquals(3, parameters.size());
         assertEquals("name1", parameters.get(0).get("name").asText());
         assertEquals("name2", parameters.get(1).get("name").asText());

Reply via email to