假设我有一个类。
public class Person {
String name;
Int age;
}
和一个该类的对象列表。
List<Person> people = ...
通常情况下,通过一个序列化器来运行这些对象,比如说 杰克逊 或 Gson 会导致这样的结果。
"[{'name':'John','age':42},{'name':'Sam','age':43}]
但我想把它序列化成一个单一的json对象 每个属性都是一个包含属性的列表,就像这样。
"{'name':['John','Sam'],'age':[42,43]}"
有哪个序列化库支持这样的功能吗?
我会创建一个 "包装器",它可以接收任意数量的人,并以一种允许它们被序列化的方式存储字段。所以在这种情况下,你会创建一系列的人员,创建一个包含这些人员的包装器,然后将其序列化。
public class PersonWrapper {
private int[] ages;
private String[] names;
public PersonWrapper(Person... persons) {
ages = new int[persons.length];
names = new String[persons.length];
for (int i = 0; i < persons.length; i++) {
ages[i] = persons[i].getAge();
names[i] = persons[i].getName();
}
}
}
转变你的 List<Person>
为新对象。
class NewClass {
List<String> name;
List<Integer> ages;
}
然后把这个对象通过Serializer来获取。"{'name':['John','Sam'],'age':[42,43]}"
序列化库一般不是为这样的东西而设计的.你要找的是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树来说,它有一个小小的惩罚. PersonWrapper
如Schred所建议的那样,可能是另一种选择,但这需要为你的所有类型提供包装器,而且一旦你的包装类发生变化,它们就需要更新。
另外,你可能也会对一些库感兴趣,如 震动 是为JSON转换而设计的(不知道在Jolt中是否可以做到)。