ここに解決策があります:
public static String writeAsSortedJson(Object object) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setNodeFactory(getArrayNodeKeyValueSortingNodeFactory());
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
String preparedJson = mapper.writeValueAsString(object);
JsonNode jsonNode = mapper.readTree(preparedJson);
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
}
@SuppressWarnings("JavaNCSS")
public static JsonNodeFactory getArrayNodeKeyValueSortingNodeFactory() {
return new JsonNodeFactory() {
@Override
public ObjectNode objectNode() {
return new ObjectNode(this, new TreeMap<String, JsonNode>());
}
@SuppressWarnings("JavaNCSS")
@Override
public ArrayNode arrayNode() {
return new ArrayNode(this, new SortedArrayList<JsonNode>(new Comparator<JsonNode>() {
@Override
public int compare(final JsonNode o1, final JsonNode o2) {
return compareRecursively(o1, o2);
}
private int compareRecursively(final JsonNode o1, final JsonNode o2) {
if (o1.isObject() && o2.isObject()) {
return compareObjectNodes(o1, o2);
} else if (o1.isObject()) {
return 1;
} else if (o2.isObject()) {
return -1;
} else if (o1.isArray() && o2.isArray()) {
return compareArrayNodes(o1, o2);
} else if (o1.isArray()) {
return 1;
} else if (o2.isArray()) {
return -1;
}
return o1.asText().compareTo(o2.asText());
}
private int compareArrayNodes(final JsonNode o1, final JsonNode o2) {
List<JsonNode> elements1 = Lists.newArrayList(o1.elements());
List<JsonNode> elements2 = Lists.newArrayList(o2.elements());
for (int i = 0; i < elements1.size() || i < elements2.size(); i++) {
if (i >= elements1.size()) {
return -1;
} else if (i >= elements2.size()) {
return 1;
}
JsonNode jsonNode1 = elements1.get(i);
JsonNode jsonNode2 = elements2.get(i);
int compareRecursively = compareRecursively(jsonNode1, jsonNode2);
if (compareRecursively != 0) {
return compareRecursively;
}
}
return 0;
}
@SuppressWarnings("ReturnCountExtended")
private int compareObjectNodes(JsonNode o1, JsonNode o2) {
List<Map.Entry<String, JsonNode>> elements1 = Lists.newArrayList(o1.fields());
List<Map.Entry<String, JsonNode>> elements2 = Lists.newArrayList(o2.fields());
if (elements1.isEmpty() && elements2.isEmpty()) {
return 0;
} else if (elements1.isEmpty()) {
return -1;
} else if (elements2.isEmpty()) {
return 1;
}
for (int i = 0; i < elements1.size() || i < elements2.size(); i++) {
if (i >= elements1.size()) {
return -1;
} else if (i >= elements2.size()) {
return 1;
}
Map.Entry<String, JsonNode> entry1 = elements1.get(i);
Map.Entry<String, JsonNode> entry2 = elements2.get(i);
int compare = entry1.getKey().compareTo(entry2.getKey());
if (compare == 0) {
int compareRecursively = compareRecursively(entry1.getValue(), entry2.getValue());
if (compareRecursively != 0) {
return compareRecursively;
}
} else {
return compare;
}
}
return 0;
}
}) { });
}
};
}
public static class SortedArrayList<T> implements List<T> {
private final List<T> delegate = new ArrayList<>();
private final Comparator<T> comparator;
public SortedArrayList(Comparator<T> comparator) {
this.comparator = comparator;
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(final Object o) {
return delegate.contains(o);
}
@NotNull
@Override
public Iterator<T> iterator() {
return delegate.iterator();
}
@NotNull
@Override
public Object[] toArray() {
return delegate.toArray();
}
@NotNull
@Override
public <T1> T1[] toArray(@NotNull final T1[] a) {
return delegate.toArray(a);
}
@Override
public boolean add(final T t) {
boolean add = delegate.add(t);
sort();
return add;
}
@Override
public void add(final int index, final T element) {
delegate.add(index, element);
sort();
}
@Override
public boolean remove(final Object o) {
boolean remove = delegate.remove(o);
sort();
return remove;
}
@Override
public T remove(final int index) {
T remove = delegate.remove(index);
sort();
return remove;
}
@Override
public boolean containsAll(@NotNull final Collection<?> c) {
return delegate.containsAll(c);
}
@Override
public boolean addAll(@NotNull final Collection<? extends T> c) {
boolean addAll = delegate.addAll(c);
sort();
return addAll;
}
@Override
public boolean addAll(int index, @NotNull Collection<? extends T> c) {
boolean addAll = delegate.addAll(index, c);
sort();
return addAll;
}
@Override
public boolean removeAll(@NotNull final Collection<?> c) {
boolean removeAll = delegate.removeAll(c);
sort();
return removeAll;
}
@Override
public boolean retainAll(@NotNull final Collection<?> c) {
boolean retainAll = delegate.retainAll(c);
sort();
return retainAll;
}
@Override
public void clear() {
delegate.clear();
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SortedArrayList<?> that = (SortedArrayList<?>) o;
return Objects.equals(delegate, that.delegate);
}
@Override
public int hashCode() {
return Objects.hash(delegate);
}
@Override
public T get(final int index) {
return delegate.get(index);
}
@Override
public T set(final int index, final T element) {
delegate.set(index, element);
sort();
return element;
}
@Override
public int indexOf(final Object o) {
return delegate.indexOf(o);
}
@Override
public int lastIndexOf(final Object o) {
return delegate.lastIndexOf(o);
}
@NotNull
@Override
public ListIterator<T> listIterator() {
return delegate.listIterator();
}
@NotNull
@Override
public ListIterator<T> listIterator(final int index) {
return delegate.listIterator(index);
}
@NotNull
@Override
public List<T> subList(final int fromIndex, final int toIndex) {
return delegate.subList(fromIndex, toIndex);
}
private void sort() {
delegate.sort(comparator);
}
}