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 <[email protected]>
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 <[email protected]>
---
.../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());