[SYNCOPE-1639] Replacing HashSet with TreeSet + Comparable
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java
index 5911ecc..937279c 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java
@@ -18,10 +18,23 @@
*/
package org.apache.syncope.client.console.audit;
+import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.StreamReadFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
import java.io.Serializable;
import java.util.Date;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.panels.MultilevelPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.JsonDiffPanel;
@@ -44,7 +57,68 @@
private static final Logger LOG = LoggerFactory.getLogger(AuditHistoryDetails.class);
- private static final ObjectMapper MAPPER = new ObjectMapper();
+ private static class SortingNodeFactory extends JsonNodeFactory {
+
+ private static final long serialVersionUID = 1870252010670L;
+
+ @Override
+ public ObjectNode objectNode() {
+ return new ObjectNode(this, new TreeMap<>());
+ }
+ }
+
+ private static class SortedSetJsonSerializer extends StdSerializer<Set<?>> {
+
+ private static final long serialVersionUID = 3849059774309L;
+
+ SortedSetJsonSerializer(final Class<Set<?>> clazz) {
+ super(clazz);
+ }
+
+ @Override
+ public void serialize(
+ final Set<?> set,
+ final JsonGenerator gen,
+ final SerializerProvider sp) throws IOException {
+
+ if (set == null) {
+ gen.writeNull();
+ return;
+ }
+
+ gen.writeStartArray();
+
+ if (!set.isEmpty()) {
+ Set<?> sorted = set;
+
+ // create sorted set only if it itself is not already SortedSet
+ if (!SortedSet.class.isAssignableFrom(set.getClass())) {
+ Object item = set.iterator().next();
+ if (Comparable.class.isAssignableFrom(item.getClass())) {
+ // and only if items are Comparable
+ sorted = new TreeSet<>(set);
+ } else {
+ LOG.debug("Cannot sort items of type {}", item.getClass());
+ }
+ }
+
+ for (Object item : sorted) {
+ gen.writeObject(item);
+ }
+ }
+
+ gen.writeEndArray();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> cast(final Class<?> aClass) {
+ return (Class<T>) aClass;
+ }
+
+ private static final ObjectMapper MAPPER = JsonMapper.builder().
+ nodeFactory(new SortingNodeFactory()).build().
+ registerModule(new SimpleModule().addSerializer(new SortedSetJsonSerializer(cast(Set.class))));
public AuditHistoryDetails(
final MultilevelPanel mlp,
@@ -114,7 +188,9 @@
? MAPPER.readTree(auditEntry.getOutput()).get("entity").toPrettyString()
: auditEntry.getBefore();
- T entity = MAPPER.readValue(content, reference);
+ T entity = MAPPER.reader().
+ with(StreamReadFeature.STRICT_DUPLICATE_DETECTION).
+ readValue(content, reference);
if (entity instanceof UserTO) {
UserTO userTO = (UserTO) entity;
userTO.setPassword(null);
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/JsonDiffPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/JsonDiffPanel.java
index 8c5b80e..2ebc7bc 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/JsonDiffPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/JsonDiffPanel.java
@@ -30,10 +30,6 @@
private static final long serialVersionUID = -5110368813584745668L;
- private final IModel<String> first;
-
- private final IModel<String> second;
-
public JsonDiffPanel(
final BaseModal<String> modal,
final IModel<String> first,
@@ -41,13 +37,13 @@
final PageReference pageRef) {
super(modal, pageRef);
- this.second = second;
- this.first = first;
- TextArea<String> jsonEditorInfoDefArea1 = new TextArea<>("jsonEditorInfo1", this.first);
- TextArea<String> jsonEditorInfoDefArea2 = new TextArea<>("jsonEditorInfo2", this.second);
+
+ TextArea<String> jsonEditorInfoDefArea1 = new TextArea<>("jsonEditorInfo1", first);
jsonEditorInfoDefArea1.setMarkupId("jsonEditorInfo1").setOutputMarkupPlaceholderTag(true);
- jsonEditorInfoDefArea2.setMarkupId("jsonEditorInfo2").setOutputMarkupPlaceholderTag(true);
add(jsonEditorInfoDefArea1);
+
+ TextArea<String> jsonEditorInfoDefArea2 = new TextArea<>("jsonEditorInfo2", second);
+ jsonEditorInfoDefArea2.setMarkupId("jsonEditorInfo2").setOutputMarkupPlaceholderTag(true);
add(jsonEditorInfoDefArea2);
}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/Attr.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/Attr.java
index a555bff..5b920ff 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/Attr.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/Attr.java
@@ -25,10 +25,11 @@
import java.util.Collection;
import java.util.List;
import javax.ws.rs.PathParam;
+import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
-public class Attr implements BaseBean {
+public class Attr implements Comparable<Attr>, BaseBean {
private static final long serialVersionUID = 4941691338796323623L;
@@ -98,6 +99,16 @@
}
@Override
+ public int compareTo(final Attr other) {
+ return equals(other)
+ ? 0
+ : new CompareToBuilder().
+ append(schema, other.schema).
+ append(values, other.values).
+ toComparison();
+ }
+
+ @Override
public int hashCode() {
return new HashCodeBuilder().
append(schema).
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
index 942ffc0..bdc9a8a 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
@@ -28,7 +28,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.ArrayList;
import java.util.Date;
-import java.util.HashSet;
+import java.util.TreeSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -82,15 +82,15 @@
private String status;
- private final Set<String> auxClasses = new HashSet<>();
+ private final Set<String> auxClasses = new TreeSet<>();
- private final Set<Attr> plainAttrs = new HashSet<>();
+ private final Set<Attr> plainAttrs = new TreeSet<>();
- private final Set<Attr> derAttrs = new HashSet<>();
+ private final Set<Attr> derAttrs = new TreeSet<>();
- private final Set<Attr> virAttrs = new HashSet<>();
+ private final Set<Attr> virAttrs = new TreeSet<>();
- private final Set<String> resources = new HashSet<>();
+ private final Set<String> resources = new TreeSet<>();
@Schema(name = "_class", required = true)
public abstract String getDiscriminator();
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
index 9b72672..921364d 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
@@ -21,9 +21,9 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
-import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
+import java.util.TreeSet;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.Attr;
@@ -35,7 +35,7 @@
private String fiql;
- private final Set<Attr> attrs = new LinkedHashSet<>();
+ private final Set<Attr> attrs = new TreeSet<>();
public String getFiql() {
return fiql;
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/DelegationTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/DelegationTO.java
index 3d567c2..36c75b7 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/DelegationTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/DelegationTO.java
@@ -22,8 +22,8 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Date;
-import java.util.HashSet;
import java.util.Set;
+import java.util.TreeSet;
import javax.ws.rs.PathParam;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -39,7 +39,7 @@
private String delegated;
- private final Set<String> roles = new HashSet<>();
+ private final Set<String> roles = new TreeSet<>();
@Schema(accessMode = Schema.AccessMode.READ_ONLY)
@Override
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/LinkedAccountTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/LinkedAccountTO.java
index 72dd158..1d149da 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/LinkedAccountTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/LinkedAccountTO.java
@@ -21,9 +21,9 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
-import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
+import java.util.TreeSet;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.Attr;
@@ -78,9 +78,9 @@
private boolean suspended;
- private final Set<Attr> plainAttrs = new HashSet<>();
+ private final Set<Attr> plainAttrs = new TreeSet<>();
- private final Set<String> privileges = new HashSet<>();
+ private final Set<String> privileges = new TreeSet<>();
@Override
public String getKey() {
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
index 591f2ad..72477b2 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
@@ -26,10 +26,10 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.TreeSet;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.BaseBean;
@@ -90,11 +90,11 @@
private String groupName;
- private final Set<Attr> plainAttrs = new HashSet<>();
+ private final Set<Attr> plainAttrs = new TreeSet<>();
- private final Set<Attr> derAttrs = new HashSet<>();
+ private final Set<Attr> derAttrs = new TreeSet<>();
- private final Set<Attr> virAttrs = new HashSet<>();
+ private final Set<Attr> virAttrs = new TreeSet<>();
public String getGroupKey() {
return groupKey;
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java
index 18bc4ad..1036ed5 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java
@@ -22,8 +22,8 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.swagger.v3.oas.annotations.media.Schema;
-import java.util.HashSet;
import java.util.Set;
+import java.util.TreeSet;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -40,7 +40,7 @@
private String entityKey;
- private final Set<String> recipients = new HashSet<>();
+ private final Set<String> recipients = new TreeSet<>();
private String sender;
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
index 6e7158f..7673f17 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
@@ -22,10 +22,8 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.ws.rs.PathParam;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -56,7 +54,7 @@
private final Map<String, AnyTO> templates = new HashMap<>();
- private final Set<String> resources = new HashSet<>();
+ private final List<String> resources = new ArrayList<>();
@Override
public String getKey() {
@@ -148,7 +146,7 @@
@JacksonXmlElementWrapper(localName = "resources")
@JacksonXmlProperty(localName = "resource")
- public Set<String> getResources() {
+ public List<String> getResources() {
return resources;
}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
index 3be4d55..bf4b22e 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
@@ -21,9 +21,9 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.TreeSet;
import javax.ws.rs.PathParam;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -34,7 +34,7 @@
private String key;
- private final Set<String> entitlements = new HashSet<>();
+ private final Set<String> entitlements = new TreeSet<>();
private final List<String> realms = new ArrayList<>();
@@ -42,7 +42,7 @@
private String dynMembershipCond;
- private final Set<String> privileges = new HashSet<>();
+ private final Set<String> privileges = new TreeSet<>();
@Override
public String getKey() {
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
index 6b46f70..0417837 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
@@ -25,10 +25,10 @@
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.ArrayList;
import java.util.Date;
-import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.TreeSet;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -70,7 +70,7 @@
private final List<String> dynRoles = new ArrayList<>();
- private final Set<String> privileges = new HashSet<>();
+ private final Set<String> privileges = new TreeSet<>();
private final List<LinkedAccountTO> linkedAccounts = new ArrayList<>();