序列化库通常不是为这样的东西而设计的。
您正在寻找的是 JSON 树转换,您可以在 Gson 和 Jackson 中轻松实现它。
这是一个 Gson 的转换示例:
final class Transformations {
private Transformations() {
}
static JsonObject transposeShallow(final Iterable<? extends JsonElement> inArray) {
final JsonObject outObject = new JsonObject();
for ( final String name : scanAllNames(inArray) ) {
final JsonArray outSubArray = new JsonArray();
for ( final JsonElement inJsonElement : inArray ) {
if ( !inJsonElement.isJsonObject() ) {
throw new IllegalArgumentException(inJsonElement + " is not a JSON object");
}
outSubArray.add(inJsonElement.getAsJsonObject().get(name));
}
outObject.add(name, outSubArray);
}
return outObject;
}
private static Iterable<String> scanAllNames(final Iterable<? extends JsonElement> jsonArray) {
final ImmutableSet.Builder<String> allNames = new ImmutableSet.Builder<>();
for ( final JsonElement jsonElement : jsonArray ) {
if ( !jsonElement.isJsonObject() ) {
throw new IllegalArgumentException(jsonElement + " is not a JSON object");
}
allNames.addAll(jsonElement.getAsJsonObject().keySet());
}
return allNames.build();
}
}
上述转换可以合并到序列化过程中,但这会影响对象的结构(例如,如何指示根对象及其字段的可转置集合?如何引入新的“转置”类型并将其合并到您的数据模型类型系统?必要时如何正确反序列化?)。
获得 JSON 树后,您可以将其转置到任何嵌套级别。
只要您不需要转换嵌套元素,转置根元素是最简单的方法。
private static final Type peopleType = new TypeToken<Collection<Person>>() {}.getType();
public static void main(final String... args) {
System.out.println(gson.toJson(people, peopleType));
System.out.println(gson.toJson(Transformations.transposeShallow(gson.toJsonTree(people, peopleType).getAsJsonArray())));
}
给出:
[{"name":"John","age":42},{"name":"Sam","age":43}]
{"name":["John","Sam"],"age":[42,43]}
上面的解决方案几乎可以处理您代码中的任何类型,但是对于构建 JSON 树有一点点损失。
Schred 建议的 PersonWrapper 之类的东西可能是另一种选择,但这需要您所有类型的包装器,并且一旦您的包装类发生更改,它们就需要更新。
此外,您可能还对像 Jolt 这样专为 JSON 转换而设计的库感兴趣(但不确定在 Jolt 中是否可行)。