lamma
lamma

Reputation: 31

Libgdx Load/save array in Json

I want to save an array of Mission.class which have variables as follows:

public class Mission {

public MissionEnum missionEnum;
public int progress;

public Mission(MissionEnum missionEnum, int progress) {
    this.missionEnum = missionEnum;
    this.progress = progress;
}

and also save missions in another java class:

public void saveMissions() {
    Json json = new Json();
    json.setOutputType(JsonWriter.OutputType.json);
    json.addClassTag("Mission", Mission.class);
    FileHandle missionFile = Gdx.files.local("missions_array.json");
    missionFile.writeString(json.prettyPrint(missions), false);
}

and load missions:

public void loadMissions() {
    if (Gdx.files.local("missions_array.json").exists()) {
        try {
            FileHandle file = Gdx.files.local("missions_array.json");
            Json json = new Json();
            json.addClassTag("Mission", Mission.class);
            missions = json.fromJson(Array.class, Mission.class, file);
            for (Mission mission : missions) {
                Gdx.app.log(TAG, "Mission loaded: " + mission.missionEnum);
            }
            Gdx.app.log(TAG, "Load missions successful");
        } catch (Exception e) {
            Gdx.app.error(TAG, "Unable to read Missions: " + e.getMessage());
        }
    }
}

I got json like this:

[
{
"class": "Mission",
"missionEnum": "BUY_POWERUP"
},
{
"class": "Mission",
"missionEnum": "DISTANCE_ONE_RUN_2"
},
{
"class": "Mission",
"missionEnum": "BANANA_TOTAL_2",
"progress": 35
}
]

However when loadMissions() is run I got the "Load missions successful" log shown but "Mission loaded..." aren't shown without any error log. Missions appeared not loaded properly. I do not know what went wrong because another array is loaded successful the same way.

Upvotes: 1

Views: 1093

Answers (2)

albodelu
albodelu

Reputation: 7981

Updated response:

Add an empty contructor and read this and this

You will either have to add a no-argument constructor to (Mission), or you will have to add a custom serializer (see https://code.google.com/p/libgdx/wiki/JsonParsing#Customizing_serialization) that knows how to save a (Mission) instance and knows the appropriate constructor to invoke when reading a (Mission) back in.

public Mission() {
    // Do nothing.
}

Reading & writing JSON

The class implementing Json.Serializable must have a zero argument constructor because object construction is done for you.

Alternatively delete the unused constructor. I think Enigo answer is also correct so I'm going to upvote his answer.

Providing Constructors for Your Classes

You don't have to provide any constructors for your class, but you must be careful when doing this. The compiler automatically provides a no-argument, default constructor for any class without constructors. This default constructor will call the no-argument constructor of the superclass. In this situation, the compiler will complain if the superclass doesn't have a no-argument constructor so you must verify that it does. If your class has no explicit superclass, then it has an implicit superclass of Object, which does have a no-argument constructor.

Note: I didn't test our responses, I have not developed games or used libgdx in the last two years.

Also read this libgdx issue: Json - constructor default value with Enum:

I don't know if this would be called a bug but, I have a case where I have an enum like this;

Then I have a class with 2 constructors;

This second gets called by my framework, the first by Json deserialization.

...

Previous response:

I guess that the missing progress field in some Mission classes can be the source of the issue but would be interesting to read the error logs to be sure.

I followed this, this and this to confirm this but it's hard without extra information about the exact log error.

Upvotes: 1

Enigo
Enigo

Reputation: 3895

Not sure why there are no errors in the logs, since while reproducing your problem I've got an exception.

The problem is in loadMissions() method: you create new Json parser without setting the class tag:

Json json = new Json();
// add the line below
json.addClassTag("Mission", Mission.class);
missions = json.fromJson(Array.class, Mission.class, file);
....

Without the tag parser doesn't know what is "class": "Mission" in json file.

Update

Another thing that may cause this issue is the args-constructor. At least, when I added it I got an exception. If you don't use it - just delete. Still, quite weird that you don't have any exceptions in logs'cos I definitely have.

Upvotes: 1

Related Questions