Fix binding of multi-feed API responses.

This commit is contained in:
dosiecki 2014-07-28 15:41:17 -07:00
parent 30dd6d0d42
commit fd2bfa02c0
5 changed files with 64 additions and 11 deletions

View file

@ -22,6 +22,7 @@ import com.newsblur.util.FeedUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Utility class for executing DB operations on the local, private NB database.
@ -175,14 +176,20 @@ public class BlurDatabaseHelper {
bulkInsertValues(DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE, socialStoryValues);
// handle classifiers
// NOTE: only handles top-level classifiers, which only show up for single-feed requests
if (apiResponse.classifiers != null) {
List<ContentValues> classifierValues = apiResponse.classifiers.getContentValues();
for (ContentValues values : classifierValues) {
values.put(DatabaseConstants.CLASSIFIER_ID, impliedFeedId);
for (Map.Entry<String,Classifier> entry : apiResponse.classifiers.entrySet()) {
// the API might not have included a feed ID, in which case it deserialized as -1 and must be implied
String classifierFeedId = entry.getKey();
if (classifierFeedId.equals("-1")) {
classifierFeedId = impliedFeedId;
}
List<ContentValues> classifierValues = entry.getValue().getContentValues();
for (ContentValues values : classifierValues) {
values.put(DatabaseConstants.CLASSIFIER_ID, classifierFeedId);
}
dbRW.delete(DatabaseConstants.CLASSIFIER_TABLE, DatabaseConstants.CLASSIFIER_ID + " = ?", new String[] { classifierFeedId });
bulkInsertValues(DatabaseConstants.CLASSIFIER_TABLE, classifierValues);
}
dbRW.delete(DatabaseConstants.CLASSIFIER_TABLE, DatabaseConstants.CLASSIFIER_ID + " = ?", new String[] { impliedFeedId });
bulkInsertValues(DatabaseConstants.CLASSIFIER_TABLE, classifierValues);
}
// handle comments

View file

@ -47,6 +47,7 @@ import com.newsblur.network.domain.StoriesResponse;
import com.newsblur.network.domain.StoryTextResponse;
import com.newsblur.network.domain.UnreadStoryHashesResponse;
import com.newsblur.serialization.BooleanTypeAdapter;
import com.newsblur.serialization.ClassifierMapTypeAdapter;
import com.newsblur.serialization.DateStringTypeAdapter;
import com.newsblur.serialization.FeedListTypeAdapter;
import com.newsblur.serialization.StoryTypeAdapter;
@ -75,6 +76,7 @@ public class APIManager {
.registerTypeAdapter(boolean.class, new BooleanTypeAdapter())
.registerTypeAdapter(Story.class, new StoryTypeAdapter())
.registerTypeAdapter(new TypeToken<List<Feed>>(){}.getType(), new FeedListTypeAdapter())
.registerTypeAdapter(new TypeToken<Map<String,Classifier>>(){}.getType(), new ClassifierMapTypeAdapter())
.create();
String appVersion = context.getSharedPreferences(PrefConstants.PREFERENCES, 0).getString(AppConstants.LAST_APP_VERSION, "unknown_version");
@ -261,8 +263,7 @@ public class APIManager {
} else if (fs.isAllSaved()) {
uri = Uri.parse(APIConstants.URL_STARRED_STORIES);
} else {
Log.wtf(this.getClass().getName(), "Asked to get stories for FeedSet of unknown type.");
return null;
throw new IllegalStateException("Asked to get stories for FeedSet of unknown type.");
}
// request params common to all stories

View file

@ -1,6 +1,7 @@
package com.newsblur.network.domain;
import java.util.List;
import java.util.Map;
import com.google.gson.annotations.SerializedName;
@ -17,7 +18,7 @@ public class StoriesResponse extends NewsBlurResponse {
@SerializedName("user_profiles")
public UserProfile[] users;
public Classifier classifiers;
public Map<String,Classifier> classifiers;
// some stories responses (like those from social feeds) also include feed data for non-subscribed feeds
@SerializedName("feeds")

View file

@ -0,0 +1,45 @@
package com.newsblur.serialization;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.newsblur.domain.Classifier;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
/**
* Special handler for the "classifiers" field that appears in API responses that is supposed to be
* a map of feed IDs to classifier objects, but sometimes is just a bare object with no feed ID if
* the API thinks we can imply it from context. This adapter re-inserts a -1 feed ID when the latter
* happens so that we don't have to write two different bindings for responses to different requests.
*/
public class ClassifierMapTypeAdapter implements JsonDeserializer<Map<String,Classifier>> {
@Override
public Map<String,Classifier> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
Map<String,Classifier> result = new HashMap<String,Classifier>();
if (jsonElement.isJsonObject()) {
JsonObject o = jsonElement.getAsJsonObject();
if (o.get("authors") != null) { // this is our hint that this is a bare classifiers object
Classifier c = (Classifier) jsonDeserializationContext.deserialize(jsonElement, Classifier.class);
result.put( "-1", c);
} else { // otherwise, we have a map of IDs to classifiers
for (Map.Entry<String, JsonElement> entry : o.entrySet()) {
Classifier c = (Classifier) jsonDeserializationContext.deserialize(entry.getValue(), Classifier.class);
result.put(entry.getKey(), c);
}
}
} else {
throw new IllegalStateException("classifiers object is not an object");
}
return result;
}
}

View file

@ -9,7 +9,6 @@ import com.newsblur.domain.Feed;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
@ -28,7 +27,7 @@ public class FeedListTypeAdapter implements JsonDeserializer<List<Feed>> {
result.add(feed);
} else if (jsonElement.isJsonArray()) {
for (JsonElement arrayMember : jsonElement.getAsJsonArray()) {
Feed feed = (Feed) jsonDeserializationContext.deserialize(jsonElement, Feed.class);
Feed feed = (Feed) jsonDeserializationContext.deserialize(arrayMember, Feed.class);
result.add(feed);
}
}