反序列化用作标志的枚举集

时间:2016-12-01 21:33:11

标签: java json serialization libgdx

我希望能够从Json设置枚举/位标志。我已设法使用包含我的枚举值的HashSet来序列化我的对象。默认情况下,LibGDX对此进行序列化,但是将类型为set的类字段添加到json,以便它知道该怎么做。我希望我的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)的方式执行某些操作。问题是,程序在read方法运行之前崩溃了。我想这是因为它在json数据中找到ArrayList但对象中的相应字段是HashSet。这是错误java.lang.IllegalArgumentException: Can not set java.util.Set field com.buckriderstudio.towercrawler.Creature.Modifier.criteriaSet to java.util.ArrayList

写作和阅读json对我来说都很重要,所以我需要他们互相合作。最后,我只是寻找一种干净的解决方案,以可读的方式获取(de)序列化EnumSet或位组合。我觉得我很接近但是我可能会尝试一种更好的技术。

我喜欢LibgDX Json实现的是字段不是必需的,可以有默认值。这会大大清理json数据,因为我有很多可以选择设置的字段。因此,这个图书馆我更喜欢说杰克逊,但我还没有和杰克逊玩过那么多。

修改

这是特别为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
    }
}

1 个答案:

答案 0 :(得分:1)

虽然这并没有完全回答我的问题,因为它在进入read方法之前仍然崩溃,我找到了一个合适的工作来使用Jackson库。我已经想出如何通过在要序列化的类上使用以下注释来忽略默认值:@JsonInclude(JsonInclude.Include.NON_DEFAULT)。这让我得到了正确的json输出,就像我在json序列化程序中使用构建一样。唯一的缺点是速度,杰克逊在一个物体上慢了大约20倍,但循环1000次使它“仅”慢了约5倍。

对于任何不知道的人,这就是你如何将杰克逊与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序列化。

如果有人知道如何在最初的问题中反序列化我的写法,我很乐意接受这个作为答案。