ContextSetJsonSerializer output should be sorted

This commit is contained in:
Luck 2020-08-14 16:25:55 +01:00
parent e2b575dd24
commit 4d5a24f2c4
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
7 changed files with 61 additions and 46 deletions

View File

@ -68,11 +68,11 @@ public class ContextsFile {
}
if (data.has("static-contexts")) {
this.staticContexts = ContextSetJsonSerializer.deserializeContextSet(data.get("static-contexts").getAsJsonObject()).immutableCopy();
this.staticContexts = ContextSetJsonSerializer.deserialize(data.get("static-contexts").getAsJsonObject()).immutableCopy();
}
if (data.has("default-contexts")) {
this.defaultContexts = ContextSetJsonSerializer.deserializeContextSet(data.get("default-contexts").getAsJsonObject()).immutableCopy();
this.defaultContexts = ContextSetJsonSerializer.deserialize(data.get("default-contexts").getAsJsonObject()).immutableCopy();
}
} catch (IOException e) {
@ -85,8 +85,8 @@ public class ContextsFile {
try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
JsonObject data = new JsonObject();
data.add("static-contexts", ContextSetJsonSerializer.serializeContextSet(this.staticContexts));
data.add("default-contexts", ContextSetJsonSerializer.serializeContextSet(this.defaultContexts));
data.add("static-contexts", ContextSetJsonSerializer.serialize(this.staticContexts));
data.add("default-contexts", ContextSetJsonSerializer.serialize(this.defaultContexts));
new GsonBuilder().setPrettyPrinting().create().toJson(data, writer);
writer.flush();

View File

@ -39,73 +39,88 @@ import net.luckperms.api.context.ContextSet;
import net.luckperms.api.context.MutableContextSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* Serializes and deserializes {@link ContextSet}s to and from JSON.
*
* <p>The entries within the serialized output are sorted, this ensures that any two invocations
* of {@link #serialize(ContextSet)} with the same {@link ContextSet} will produce
* the same exact JSON string.</p>
*/
public final class ContextSetJsonSerializer {
private ContextSetJsonSerializer() {}
public static JsonObject serializeContextSet(ContextSet contextSet) {
JsonObject data = new JsonObject();
Map<String, Set<String>> map = contextSet.toMap();
public static JsonObject serialize(ContextSet contextSet) {
JsonObject output = new JsonObject();
for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
List<String> values = new ArrayList<>(entry.getValue());
int size = values.size();
List<Map.Entry<String, Set<String>>> entries = new ArrayList<>(contextSet.toMap().entrySet());
entries.sort(Map.Entry.comparingByKey()); // sort - consistent output order
if (size == 1) {
data.addProperty(entry.getKey(), values.get(0));
} else if (size > 1) {
JsonArray arr = new JsonArray();
for (String s : values) {
arr.add(new JsonPrimitive(s));
}
data.add(entry.getKey(), arr);
for (Map.Entry<String, Set<String>> entry : entries) {
String[] values = entry.getValue().toArray(new String[0]);
switch (values.length) {
case 0:
break;
case 1:
output.addProperty(entry.getKey(), values[0]);
break;
default:
Arrays.sort(values); // sort - consistent output order
JsonArray arr = new JsonArray();
for (String value : values) {
arr.add(new JsonPrimitive(value));
}
output.add(entry.getKey(), arr);
break;
}
}
return data;
return output;
}
public static ContextSet deserializeContextSet(Gson gson, String json) {
Objects.requireNonNull(json, "json");
if (json.equals("{}")) {
public static ContextSet deserialize(Gson gson, String input) {
Objects.requireNonNull(input, "input");
if (input.equals("{}")) {
return ImmutableContextSetImpl.EMPTY;
}
JsonObject context = gson.fromJson(json, JsonObject.class);
if (context == null) {
JsonObject jsonObject = gson.fromJson(input, JsonObject.class);
if (jsonObject == null) {
return ImmutableContextSetImpl.EMPTY;
}
return deserializeContextSet(context);
return deserialize(jsonObject);
}
public static ContextSet deserializeContextSet(JsonElement element) {
public static ContextSet deserialize(JsonElement element) {
Preconditions.checkArgument(element.isJsonObject());
JsonObject data = element.getAsJsonObject();
JsonObject jsonObject = element.getAsJsonObject();
if (data.entrySet().isEmpty()) {
if (jsonObject.size() == 0) {
return ImmutableContextSetImpl.EMPTY;
}
MutableContextSet map = new MutableContextSetImpl();
for (Map.Entry<String, JsonElement> e : data.entrySet()) {
String k = e.getKey();
JsonElement v = e.getValue();
MutableContextSet contextSet = new MutableContextSetImpl();
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
String k = entry.getKey();
JsonElement v = entry.getValue();
if (v.isJsonArray()) {
JsonArray values = v.getAsJsonArray();
for (JsonElement value : values) {
map.add(k, value.getAsString());
contextSet.add(k, value.getAsString());
}
} else {
map.add(k, v.getAsString());
contextSet.add(k, v.getAsString());
}
}
return map;
return contextSet;
}
}

View File

@ -61,7 +61,7 @@ public class NodeJsonSerializer {
}
if (!node.getContexts().isEmpty()) {
attributes.add("context", ContextSetJsonSerializer.serializeContextSet(node.getContexts()));
attributes.add("context", ContextSetJsonSerializer.serialize(node.getContexts()));
}
arr.add(attributes);
@ -84,7 +84,7 @@ public class NodeJsonSerializer {
}
if (attributes.has("context")) {
builder.context(ContextSetJsonSerializer.deserializeContextSet(attributes.get("context")));
builder.context(ContextSetJsonSerializer.deserialize(attributes.get("context")));
}
nodes.add(builder.build());

View File

@ -93,7 +93,7 @@ public final class SqlNode {
world = "global";
}
return new SqlNode(permission, value, server, world, expiry, ContextSetJsonSerializer.deserializeContextSet(GsonProvider.normal(), contexts).immutableCopy(), sqlId);
return new SqlNode(permission, value, server, world, expiry, ContextSetJsonSerializer.deserialize(GsonProvider.normal(), contexts).immutableCopy(), sqlId);
}
private final String permission;

View File

@ -759,7 +759,7 @@ public class SqlStorage implements StorageImplementation {
ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry());
ps.setString(7, GsonProvider.normal().toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.setString(7, GsonProvider.normal().toJson(ContextSetJsonSerializer.serialize(nd.getContexts())));
}
private static Set<SqlNode> getMissingFromRemote(Set<SqlNode> local, Set<SqlNode> remote) {

View File

@ -127,7 +127,7 @@ public final class WebEditor {
})
)
.consume(o -> {
o.add("potentialContexts", ContextSetJsonSerializer.serializeContextSet(potentialContexts.build()));
o.add("potentialContexts", ContextSetJsonSerializer.serialize(potentialContexts.build()));
})
.toJson();
}

View File

@ -122,7 +122,7 @@ public class SubjectDataContainer {
JsonObject context = section.get("context").getAsJsonObject();
JsonObject data = section.get("data").getAsJsonObject();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).immutableCopy();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserialize(context).immutableCopy();
ImmutableMap.Builder<String, Boolean> perms = ImmutableMap.builder();
for (Map.Entry<String, JsonElement> perm : data.entrySet()) {
perms.put(perm.getKey(), perm.getValue().getAsBoolean());
@ -145,7 +145,7 @@ public class SubjectDataContainer {
JsonObject context = section.get("context").getAsJsonObject();
JsonObject data = section.get("data").getAsJsonObject();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).immutableCopy();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserialize(context).immutableCopy();
ImmutableMap.Builder<String, String> opts = ImmutableMap.builder();
for (Map.Entry<String, JsonElement> opt : data.entrySet()) {
opts.put(opt.getKey(), opt.getValue().getAsString());
@ -168,7 +168,7 @@ public class SubjectDataContainer {
JsonObject context = section.get("context").getAsJsonObject();
JsonArray data = section.get("data").getAsJsonArray();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).immutableCopy();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserialize(context).immutableCopy();
ImmutableList.Builder<LPSubjectReference> pars = ImmutableList.builder();
for (JsonElement p : data) {
if (!p.isJsonObject()) {
@ -203,7 +203,7 @@ public class SubjectDataContainer {
}
JsonObject section = new JsonObject();
section.add("context", ContextSetJsonSerializer.serializeContextSet(e.getKey()));
section.add("context", ContextSetJsonSerializer.serialize(e.getKey()));
JsonObject data = new JsonObject();
@ -227,7 +227,7 @@ public class SubjectDataContainer {
}
JsonObject section = new JsonObject();
section.add("context", ContextSetJsonSerializer.serializeContextSet(e.getKey()));
section.add("context", ContextSetJsonSerializer.serialize(e.getKey()));
JsonObject data = new JsonObject();
@ -251,7 +251,7 @@ public class SubjectDataContainer {
}
JsonObject section = new JsonObject();
section.add("context", ContextSetJsonSerializer.serializeContextSet(e.getKey()));
section.add("context", ContextSetJsonSerializer.serialize(e.getKey()));
JsonArray data = new JsonArray();
for (LPSubjectReference ref : e.getValue()) {