java - 反序列化一组枚举以用作标志

标签 java json serialization libgdx

我希望能够从 Json 设置枚举/位标志。我已成功使用包含枚举值的 HashSet 序列化我的对象。默认情况下,LibGDX 会序列化它,但会向 json 添加一个类型为 set 的类字段,以便它知道要做什么。我希望我的 json 是干净的并且与 java 解耦,所以我编写了这个类:

public class CriteriaSerializer implements Json.Serializer<HashSet> {

    @Override
    public void write(Json json, HashSet object, Class knownType) {
        json.writeArrayStart();
        for (Object o : object)
        {
            if (o instanceof Modifier.Criteria) {
                json.writeValue(o, Modifier.Criteria.class);
            }
        }
        json.writeArrayEnd();
    }

    @Override
    public HashSet read(Json json, JsonValue jsonData, Class type) {
        System.out.println("Running!?");
        HashSet<Modifier.Criteria> criteriaSet = new HashSet<Modifier.Criteria>();

        for (JsonValue entry = jsonData.child; entry != null; entry = entry.next)
        {
            criteriaSet.add(Modifier.Criteria.valueOf("ADD"));//Modifier.Criteria.valueOf(entry.asString()));
        }

        return criteriaSet;
    }
}

write 方法会产生以下输出:

modifier: {
    amount: 1 //Other field
    criteriaSet: [
        RED
        BLUE
    ]

我需要的只是将这些值作为字符串获取,这样我就可以按照 myCriteriaSet.put(Criteria.valueOf(output) 的方式做一些事情。问题是,程序在读取之前崩溃了方法正在运行,我猜这是因为它在json数据中找到了ArrayList,但对象中对应的字段是HashSet,这是错误java .lang.IllegalArgumentException:无法将 java.util.Set 字段 com.buckriderstudio.towercrawler.Creature.Modifier.criteriaSet 设置为 java.util.ArrayList

写入和读取 json 对我来说都很重要,所以我需要它们互相协作。最后,我只是在寻找一个干净的解决方案,以可读的方式获取(反)序列化 EnumSet 或位组合。我觉得我已经很接近了,但可能有比我正在尝试的更好的技术。

我喜欢 LibgDX Json 实现的一点是字段不是强制性的并且可以有默认值。这会大大清理 json 数据,因为我有很多可以选择设置的字段。因此,这个库我更喜欢说 Jackson,但我并没有经常使用 Jackson。

编辑

这是专门为 Andreas 所做的编辑。据我所知(但我可能是错的)这与实际问题无关。 Andreas 向我解释 Json 语法是错误的,事实是它甚至没有到达我的 read 方法,并且 LibGDX 附带的 json 库没有编写 100% 正确的 Json。有必要吗?也许是为了命名 Json?需要工作吗?我不这么认为。

这是我的测试。我所做的就是创建这个 Creature 对象并用 1 行代码解析它。解析此内容时不涉及我的个人代码。

Creature c = new Creature("MadMenyo");
System.out.println(json.prettyPrint(c));

//Output

{
name: MadMenyo
modifier: {
    amount: 1
    criteriaSet: {
        class: java.util.HashSet
        items: [
            VS_NATURE
            MULTIPLY
        ]
    }
}
stats: {
    ENDURANCE: {
        abbreviation: END
        displayName: Endurance
        baseValue: 8
        finalValue: 8
    }
    MAGIC: {
        abbreviation: MP
        displayName: Your mana
        baseValue: 20
        finalValue: 20
    }
    STRENGTH: {
        baseValue: 6
        finalValue: 6
    }
    HEALTH: {
        abbreviation: HP
        displayName: Your life
        baseValue: 100
        finalValue: 100
    }
}
}

//Looks like no valid Json to me. But the following line parses that correctly into a Creature object.

Creature jsonCreature = json.fromJson(Creature.class, jsonCreature);

在我们进一步偏离之前。我不想使用它的原因是因为它输出类 class: java.util.HashSet 并且我很确定这是不必要的。

编辑

添加以下代码行后,我成功输出了正确的 json。然而,代码在到达我的自定义读取方法之前仍然会中断。问题仍然是如何解决这个问题,或者如何以不同的方式序列化 Enumset 或其他保存枚举的 Set,只要它在 Json 中可读并且可以用作标志。

    JsonWriter jw = new JsonWriter(new StringWriter());
    json.setOutputType(JsonWriter.OutputType.json);
    json.setWriter(jw);

//Now outputs proper Json

{
"name": "MadMenyo",
"modifier": {
    "amount": 1,
    "criteriaSet": [
        "VS_NATURE",
        "MULTIPLY"
    ]
},
"stats": {
    "ENDURANCE": {
        "abbreviation": "END",
        "displayName": "Endurance",
        "baseValue": 8,
        "finalValue": 8
    },
    "MAGIC": {
        "abbreviation": "MP",
        "displayName": "Your mana",
        "baseValue": 20,
        "finalValue": 20
    },
    "STRENGTH": {
        "baseValue": 6,
        "finalValue": 6
    },
    "HEALTH": {
        "abbreviation": "HP",
        "displayName": "Your life",
        "baseValue": 100,
        "finalValue": 100
    }
}

最佳答案

尽管这并不能完全回答我的问题,因为它在到达 read 方法之前仍然崩溃,但我已经找到了使用 Jackson 库的合适解决方法。我已经弄清楚如何通过在要序列化的类上使用以下注释来忽略默认值:@JsonInclude(JsonInclude.Include.NON_DEFAULT)。这让我得到了准确的 json 输出,就像我在 json 序列化器中尝试构建的那样。唯一的缺点是速度,Jackson 在单个对象上大约慢了 20 倍,但循环 1000 次使它“仅”慢了大约 5 倍。

对于任何不知道的人,这就是将 Jackson 与 LibGDX 集成的方式:

build中添加对核心项目的依赖项。

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.0.1'

开始解析只需要几行。

    ObjectMapper mapper = new ObjectMapper();
    //Add pretty print indentation
    mapper.enable(SerializationFeature.INDENT_OUTPUT);

    //When serializing we have to wrap it in a try/catch signature
    try {
        mapper.writeValue(Gdx.files.local("creature.json").file(), creature);
    } catch (IOException e) {
        e.printStackTrace();
    }

    //To map it back to a object we do the same
    Creature jsonCreature = null;
    try {
        jsonCreature = mapper.readValue(Gdx.files.local("creature.json").readString(), Creature.class);
    } catch (IOException e) {
        e.printStackTrace();
    }

    //Jackson also has control over what you want to serialize
    mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
    //Or with annotation in front of the class
    @JsonIgnoreProperties({"nameOfProperty", "anotherProperty"})

这一切至少给了我与 json 序列化器中构建相同的功能,并且它立即序列化 EnumSet

如果有人知道如何在最初的问题中反序列化我的写入方法,我会很高兴接受这个答案。

关于java - 反序列化一组枚举以用作标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40920794/

相关文章:

java - 配置 Java GUI 应用程序的响应能力

java - 如何使用 Jsoup 将不允许的 html 标签分隔符转换为存在不允许的标签的实体

java - 如何从 AngularJS 调用 Restful 服务

c# - 如何反序列化一个xml字符串

c# - protobuf-net 中枚举的二进制表示

java - 如何使用 ClickListener 在 Android Studio 中设置起始标记位置?

javascript - 如何使用 PHP 更新 JSON 文件中的值

json - 配置jacksonObjectMapper在Spring MVC 3中不起作用

javascript - 当传递的键是变量时从 json 获取值

java - Jackson 自定义解串器委托(delegate)恢复为默认值