Custom deserializer for RealmObject

爷,独闯天下 提交于 2019-12-25 16:55:35

问题


For learning purposes i'm creating an android app by using Realm and the Edinburg Festival Api. It's going pretty well except for one problem.

I'm using the following to convert the retrieved JSON to RealmObjects:

public void onResponse(final String response) {
    realm.executeTransactionAsync(new Realm.Transaction(){
        @Override
        public void execute(Realm realm) {
            // Update our realm with the results
            parseImages();
            realm.createOrUpdateAllFromJson(Festival.class, response);
        }
    }
}

This works fine except for one field, the images. The image part of the JSON:

"images": {    
    "031da8b4bad1360eddea87e8820615016878b183": {
        "hash": "031da8b4bad1360eddea87e8820615016878b183",
        "orientation": "landscape",
        "type": "hero",
        "versions": {
            "large-1024": {
            "height": 213,
            "mime": "image/png",
            "type": "large-1024",
        }
        "width": 1024
    }
}

The problem here is the hash inside the image object. I have no clue how to handle this. The hash is different for every festival. Would it be possible to to make a custom JSON deserializer in my RealmObject?

Last code sample is my current model:

public class Festival extends RealmObject {
    @PrimaryKey
    public String title;
    RealmList<Image> images;
    public String description_teaser;
    public String description;
    public String genre;
    public String age_category;
    public String website;
    public RealmList<Performance> performances;
    public int votes;
}

I'm aware my PK is not optimal but this is still just testing to get the images working and i needed to set a PK for migrating.

Any tips are welcome, cheers :)

Update

Added the image model:

public class Image extends RealmObject {
    public String hash;
    public String orientation;
    public String type;
    RealmList<Version> versions;
}

Update 2

My attempt to parse the images before calling realm.createOrUpdateAllFromJson(Festival.class, response);

private void parseImages(String jsonString) throws JSONException {
    JSONArray jsonArr = new JSONArray(jsonString);
    for(int i = 0; i < jsonArr.length(); i++){
        JSONObject jsonObj = jsonArr.getJSONObject(i);
        JSONObject images = (JSONObject)jsonObj.get("images");
        Iterator<String> iter = images.keys();
        while (iter.hasNext()) {
            String key = iter.next();
            try {
                JSONObject value = json.get(key);
                realm.createOrUpdateObjectFromJson(Image.class,value);
            } catch (JSONException e) {
                // Something went wrong!
            }
        }
    }
}

Update 3

I created a function that cleans up the broken JSON i get from the API. It ain't very nice but it works for now. it removes the hashes and the wierd versions and just places them both in a array. I'm sure it could be more efficiently written but i'll just go with this so i can move on with the rest of my app for now. See my own answer.


回答1:


my own temporary solution:

    /**
     * Function to fix the json coming from the Festival API
     * This is a bit more complicated then it needs to be but realm does not yet support @Serializedname
     * It removes the "large-1024" (and simllar) object and places the versions in a JSON version array
     * Then it removes the hashes and creates and images array. The JsonArray can now be parsed normally :)
     *
     * @param jsonString Result string from the festival api
     * @return JSONArray The fixed JSON in the form of a JSONArray
     * @throws JSONException
     */
    private JSONArray cleanUpJson(String jsonString) throws JSONException {
        JSONArray json = new JSONArray(jsonString);
        for(int i = 0; i < json.length(); i++){
            // We store the json Image Objects in here so we can remove the hashes
            Map<String,JSONObject> images = new HashMap<>();
            JSONObject festivalJson = json.getJSONObject(i);
            JSONObject imagesJson = (JSONObject)festivalJson.get("images");
            // Iterate each hash inside the images
            Iterator<String> hashIter = imagesJson.keys();
            while (hashIter.hasNext()) {
                String key = hashIter.next();
                try {
                    final JSONObject image = imagesJson.getJSONObject(key);

                    // Remove the version parents and map them to version
                    Map<String, JSONObject> versions = new HashMap<>();
                    JSONObject versionsJsonObject = image.getJSONObject("versions");

                    // Now iterate all the possible version and map add to the hashmap
                    Iterator<String> versionIter = versionsJsonObject.keys();
                    while(versionIter.hasNext()){
                        String currentVersion = versionIter.next();
                        versions.put(currentVersion,versionsJsonObject.getJSONObject(currentVersion));
                    }

                    // Use the hashmap to modify the json so we get an array of version
                    // This can't be done in the iterator because you will get concurrent error
                    image.remove("versions");
                    Iterator hashMapIter = versions.entrySet().iterator();
                    JSONArray versionJsonArray = new JSONArray();
                    while( hashMapIter.hasNext() ){
                        Map.Entry pair = (Map.Entry)hashMapIter.next();
                        versionJsonArray.put(pair.getValue());
                    }
                    image.put("versions",versionJsonArray);
                    Log.d(LOG_TAG,image.toString());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                images.put(key,imagesJson.getJSONObject(key));
            }
            // Now let's get rid of the hashes
            Iterator hashMapIter = images.entrySet().iterator();
            JSONArray imagesJsonArray = new JSONArray();
            while( hashMapIter.hasNext() ){
                Map.Entry pair = (Map.Entry)hashMapIter.next();
                imagesJsonArray.put(pair.getValue());
            }
            festivalJson.put("images", imagesJsonArray);
        }
        return json;
    }

Hope it helps someone :) But sure ain't neat.




回答2:


Due to how the keys are dynamic in this JSON (why isn't this an array? Whoever designed this API had no idea what they were doing), you'll have to manually parse the object up to the point of the hash key:

JSONObject jsonObj = new JSONObject(jsonString);
JSONObject images = (JSONObject)jsonObj.get("images");
Iterator<String> iter = images.keys();
while (iter.hasNext()) {
    String key = iter.next();
    try {
        JSONObject value = json.get(key);
        realm.createOrUpdateObjectFromJson(Image.class, value.toString());
    } catch (JSONException e) {
        // Something went wrong!
    }
}


来源:https://stackoverflow.com/questions/40535188/custom-deserializer-for-realmobject

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!