meraki-analytics / orianna

A Java framework for the Riot Games League of Legends API (http://developer.riotgames.com/).
MIT License
182 stars 56 forks source link

Serialization of Champions #32

Closed JeffreyCA closed 9 years ago

JeffreyCA commented 9 years ago

I serialize an object of List<Champion> and save it to a file named champions. I use the following code to read that file and save it to List<Champion> champion. How do I use champion to be used by future API requests?

try {
    FileInputStream fileInputStream = mContext.openFileInput("champions");
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    List<Champion> champion = (List<Champion>) objectInputStream.readObject();
    objectInputStream.close();
    fileInputStream.close();
} catch (IOException e) {
    e.printStackTrace();
}

I have the following code somewhere else and it does not seem to be using the champion data I loaded from the file: String champion_name = par.get(position_number).getChampion().getName();

I wish to only use RiotAPI.getChampions(); once, when saving it to a file.

robrua commented 9 years ago

Look into the DataStore interface. It's the tool in Orianna designed to do persistent storage. There's a FileSystem implementation in there already (though it was written hastily and may be a little buggy), and https://github.com/robrua/orianna-hibernate has an implementation for databases.

JeffreyCA commented 9 years ago

I don't really get it. How would I initialize everything? I just wanted to load a champions list.

Do I do something with this?

@Override
        protected boolean allowsNullStoreKeys() {
            return false;
        }

        @Override
        protected <T extends OriannaObject<?>> boolean checkHasAll(Class<T> aClass) {
            return false;
        }

        @Override
        protected <T extends OriannaObject<?>> void doDelete(Class<T> aClass, List<?> list) {

        }

        @Override
        protected <T extends OriannaObject<?>> void doDelete(Class<T> aClass, Object o) {

        }

        @Override
        protected <T extends OriannaObject<?>> List<T> doGet(Class<T> aClass, List<?> list) {
            return null;
        }

        @Override
        protected <T extends OriannaObject<?>> T doGet(Class<T> aClass, Object o) {
            return null;
        }

        @Override
        protected <T extends OriannaObject<?>> List<T> doGetAll(Class<T> aClass) {
            return null;
        }

        @Override
        protected <T extends OriannaObject<?>> CloseableIterator<T> doGetIterator(Class<T> aClass) {
            return null;
        }

        @Override
        protected <T extends OriannaObject<?>> void doStore(List<T> list, List<?> list1, boolean b) {

        }

        @Override
        protected <T extends OriannaObject<?>> void doStore(T t, Object o) {

        }
robrua commented 9 years ago

If you want the saved champion data to be used for getChampion() and similar functions, you'll need to use a DataStore (unless you want to use getChampionID() and search your saved list for that ID).

RiotAPI.setDataStore() accepts any DateStore implementation and will replace the in-memory cache with that. You could do RiotAPI.setDataStore(new FileSystemDB("/data/store/path")); to store things locally on disk with serialized files (As a warning, this implementation probably has some bugs). You could also use the Hibernate bindings from orianna-hibernate or write your own custom DataStore.

JeffreyCA commented 9 years ago

I still want to use into FileSystemDB, despite the bugs.

FileSystemDB fileSystemDB = new FileSystemDB(mContext.getFilesDir().getPath());
DataStore ds = fileSystemDB;

Then to store it I use ds.store(new OriannaObject<com.robrua.orianna.type.core.staticdata.Champion>, ""); and replace my FileOutputStream code with that:?

List<Champion> champions = RiotAPI.getChampions();

try {
    FileOutputStream fileOutputStream = mContext.openFileOutput("champions", Context.MODE_PRIVATE);
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    objectOutputStream.writeObject(champions);
    objectOutputStream.close();
    fileOutputStream.close();

} catch (IOException ee) {
    e.printStackTrace();
}

Then later on I have RiotAPI.setDataStore(ds);

robrua commented 9 years ago

champions, items, runes, masteries, summoner spells, summoners, and matches are automatically cached behind the scenes just by setting the data store. You won't need to save or load anything manually, just call RiotAPI.getChampions() again and it'll give you the saved version instead of making a new call to Riot.

JeffreyCA commented 9 years ago

Okay, I have this, and it's not working:

I set datastore, and then read the file champions located at /data/data/com.example.jeffrey.leagueoflegendslive/files and save it to the List<Champion> champion.

RiotAPI.setDataStore(new FileSystemDB("/data/data/com.example.jeffrey.leagueoflegendslive/files"));
           try {
                FileInputStream fileInputStream = mContext.openFileInput("champions");
                ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
                List<Champion> champion = (List<Champion>) objectInputStream.readObject();

                objectInputStream.close();
                fileInputStream.close();
                RiotAPI.getChampions();
            } catch (IOException e) {
              }
robrua commented 9 years ago

Why are you trying to read the file it created manually? When you call getChampions() the first time it'll hit the API and store it in a file automatically. Every time you call it again after that it'll read the file and get you the champions automatically without hitting the API

JeffreyCA commented 9 years ago

Thank you!

This is part of what I have now:

RiotAPI.setDataStore(new FileSystemDB("/data/data/com.example.jeffrey.leagueoflegendslive/files"));
RiotAPI.getChampions();

Later I do: CurrentGame cg = RiotAPI.getCurrentGame(name); and List<Participant> participant = cg,getParticipants();

After implementing the DataStore, if I do: participant.get(pos).getChampion();, it still performs an API request.

On the other hand, if I do: participant.get(pos).getSummonerName();, it does not perform an API request.

Here's the error log I got from a NetworkOnMainThreadException (sign of performing a network request):

at com.robrua.orianna.api.dto.BaseRiotAPI.get(BaseRiotAPI.java:206)
            at com.robrua.orianna.api.dto.BaseRiotAPI.get(BaseRiotAPI.java:166)
            at com.robrua.orianna.api.dto.StaticDataAPI.getChampion(StaticDataAPI.java:39)
            at com.robrua.orianna.api.dto.BaseRiotAPI.getChampion(BaseRiotAPI.java:274)
            at com.robrua.orianna.api.core.StaticDataAPI.getChampionByID(StaticDataAPI.java:47)
            at com.robrua.orianna.api.core.RiotAPI.getChampionByID(RiotAPI.java:66)
            at com.robrua.orianna.type.core.currentgame.Participant.getChampion(Participant.java:55)

Without the DataStore, participant.get(pos).getChampion(); would not perform another request to the API, after having done getParticipants() and getChampions() previously.

robrua commented 9 years ago

Hey - I dug into this and it was due to a bug w/FileSystemDB where records were being stored by hashcode of their class, which isn't always stable. It's been switched to canonical class name now, so this bug should be fixed in the latest snapshot

JeffreyCA commented 9 years ago

Great, thank you! :+1: