序列化对象列表,按属性键

时间:2020-05-15 18:13:06

标签: java json serialization jackson gson

说我有一堂课:

public class Person {
   String name;
   Int age;
}

以及此类的对象列表:

List<Person> people = ...

通常,通过诸如 Jackson Gson 之类的序列化程序运行此命令会导致以下结果:

"[{'name':'John','age':42},{'name':'Sam','age':43}]

但是我要序列化为单个json对象,其中每个属性都是包含属性的列表,像这样:

"{'name':['John','Sam'],'age':[42,43]}"

任何序列化库都支持吗?

3 个答案:

答案 0 :(得分:1)

我将创建一种“包装程序”,该程序可以容纳任意数量的人员并以一种可以使他们序列化的方式存储字段。因此,在这种情况下,您将创建一系列人员,创建包含这些人员的包装,然后对其进行序列化。

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();
        }
    }
}

答案 1 :(得分:0)

将您的<preference name="android-minSdkVersion" value="19" /> <preference name="android-maxSdkVersion" value="29" /> <preference name="android-targetSdkVersion" value="29" /> 转换为新对象。

List<Person>

然后将该对象传递给序列化器以获取: class NewClass { List<String> name; List<Integer> ages; }

答案 2 :(得分:0)

序列化库通常不是为类似的东西设计的。 您正在寻找的是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中是否可行)。