Nicholas Muir
Nicholas Muir

Reputation: 3124

Object conversion to Json String and conversion back to object failing with missing DateTime element Android

I am trying to save an object into shared preferences and then retrieve.

The object consists of single DateTime for the current day, and a List of objects for the biggest stock losers (stock symbols as a string, and percentage change as a double).

The object model is:

public class DayLosersSharedPreference {

    LocalDateTime dateTime;
    List<PercentageChange> percentageChangesList;

    public LocalDateTime getDateTime() {
        return dateTime;
    }

    public void setDateTime(LocalDateTime dateTime) {
        this.dateTime = dateTime;
    }

    public List<PercentageChange> getPercentageChangesList() {
        return percentageChangesList;
    }

    public void setPercentageChangesList(List<PercentageChange> percentageChangesList) {
        this.percentageChangesList = percentageChangesList;
    }
}

The single object (containing DateTime and object List) is passed to my shared preferences class for storage like this:

public class SharedPreferences {

    Context context = MySuperAppApplication.getContext();
    android.content.SharedPreferences sharedPreferences = context.getSharedPreferences(STRINGS.LOSERS_SP(), Context.MODE_PRIVATE);
    Gson gson = new Gson();

    public void storeLosers(DayLosersSharedPreference losers) {

        System.out.println("Object being stored date: " + losers.getDateTime());
        System.out.println("Object being stored array: " + losers.getPercentageChangesList());

        String dailyLosersJson = gson.toJson(losers);

        System.out.println("Object being stored as Json String: " + dailyLosersJson);

        sharedPreferences.edit()
                .putString(STRINGS.DAILY_LOSERS_SP(), dailyLosersJson)
                .apply();
    }
}

The output of the println()'s shows the object before the Json String conversion is fine:

I/System.out: Object being stored date: 2019-03-18T00:00
I/System.out: Object being stored array: [com.roboticc.alpha.Models.PercentageChange@8bef7ab, com.roboticc.alpha.Models.PercentageChange@207be08, com.roboticc.alpha.Models.PercentageChange@b6289a1, com.roboticc.alpha.Models.PercentageChange@269d7c6, com.roboticc.alpha.Models.PercentageChange@ff36387, com.roboticc.alpha.Models.PercentageChange@45eb2b4, com.roboticc.alpha.Models.PercentageChange@1fd1edd, com.roboticc.alpha.Models.PercentageChange@41baa52, com.roboticc.alpha.Models.PercentageChange@b18b123, com.roboticc.alpha.Models.PercentageChange@38e4620]

But there is a problem in how I am converting this to a Json string. When I look at the output after it was converted it loses the DateTime element:

I/System.out: Object being stored as Json String: {"dateTime":{},"percentageChangesList":[{"percentageChange":-0.15908367801463796,"symbol":"AAL"},{"percentageChange":0.0,"symbol":"AAME"},{"percentageChange":0.19011406844106543,"symbol":"AABA"},{"percentageChange":0.500000000000002,"symbol":"AAOI"},{"percentageChange":0.6455517450070613,"symbol":"AAWW"},{"percentageChange":0.8957770510450668,"symbol":"AAXJ"},{"percentageChange":1.0208467655276197,"symbol":"AAPL"},{"percentageChange":1.081223628691974,"symbol":"ABCB"},{"percentageChange":2.0748867159551576,"symbol":"AAON"},{"percentageChange":4.29524603836531,"symbol":"AAXN"}]}

Once I retrieve it from shared preferences, predictably I get a null pointer on the date time as it is not being saved but can access the percentage change list.

I assume it is something wrong with how I am converting from object to Json string, do I have to do something like pass the model type? or can DateTime not be stored in Json in that format?

Thanks for your help

EDIT: I was able to change the DateTime to a string and the convert back after retrieval to fix this. I am still interested why this doesn't work directly without DateTime conversion. Especially considering a whole List of objects can be passed.

Upvotes: 0

Views: 192

Answers (1)

Vardaan Sharma
Vardaan Sharma

Reputation: 1165

gson is not aware of LocalDateTime objects and hence fails to parse it. If you do want it to directly parse LocalDateTime without having to convert it to a String first you will have to tell gson HOW to parse LocalDateTime using registerTypeAdaptor.

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
    @Override
    public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        Instant instant = Instant.ofEpochMilli(json.getAsJsonPrimitive().getAsLong());
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }
}).create();

This is something that the newer versions of GSON might be able to handle though: https://github.com/google/gson/pull/1266/files

I'm not sure if the above commit has been published into any of their releases, but it sure does look like some duture version will be able to handle this automatically.

Upvotes: 1

Related Questions