2016-11-10 4 views
0

Для обучения я создаю приложение для Android с помощью Realm и Edinburg Festival Api. Все идет хорошо, за исключением одной проблемы.Пользовательский десериализатор для RealmObject

Я использую следующие преобразовать извлеченное JSON в 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); 
     } 
    } 
} 

Это прекрасно работает для одного поля, изображений, за исключением. Образная часть JSON:

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

Проблема заключается в том, что хэш внутри объекта изображения. Я понятия не имею, как справиться с этим. Хэш отличается для каждого фестиваля. Можно ли создать собственный десериализатор JSON в моем RealmObject?

Последний пример кода моя текущая модель:

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; 
} 

Я знаю, мой ПК не является оптимальным, но это еще только тестирование, чтобы получить изображения рабочих и мне нужно, чтобы установить ПК для миграции.

Любые советы приветствуются, ура :)

Обновление

Добавлена ​​модель изображения:

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

Update 2

Моя попытка разобрать изображения перед вызовом realm.createOrUpdateAllFromJson (Festival.class, ответ);

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

Я создал функцию, которая чистит сломанную JSON я получаю от API. Это не очень приятно, но сейчас это работает. он удаляет хеши и версии wierd и просто помещает их в массив. Я уверен, что это может быть более эффективно написано, но я просто займусь этим, чтобы я мог продолжить работу с остальной частью моего приложения. См. Мой собственный ответ.

ответ

1

свое собственное временное решение:

/** 
    * 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; 
    } 

Надеюсь, это поможет кому-то :) Но уверен, что это не опрятно.

+0

Nice one - ------ – EpicPandaForce

0

Благодаря тому, как клавиши динамичны в этом формате JSON (почему не это массив Кто предназначен этот API не имел ни малейшего представления, что они делают?), 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! 
    } 
} 
+0

Спасибо за ваш ответ. Как бы я совместить это с текущим способом, я разбираю json? Должны ли i @ignore изображения, а затем запускать этот код после добавления изображений? Или я могу каким-то образом реализовать это внутри realm.createOrUpdateAllFromJson? – Juxture

+0

Вам нужно будет запустить этот код, прежде чем подавать его на 'createOrUpdateAllFromJson' –

+0

Каждый объект изображения должен храниться отдельно как объект при разборе изображений один за другим по ключу. Сам хэш также может быть найден в объекте, поэтому вы не теряете никакой информации. 'createOrUpdateAll' ожидает массив, но это не массив. – EpicPandaForce