/ / Gson analizuje obiekt mapy bez klucza - android, json, gson, retrofit2

Gson analizuje obiekt mapy bez klucza - android, json, gson, retrofit2

Czy ktoś może mi wyjaśnić, jak mogę analizować JSON?

{
"5": {
"NumPossibleAchievements": "2",
"PossibleScore": "15",
"NumAchieved": 0,
"ScoreAchieved": 0,
"NumAchievedHardcore": 0,
"ScoreAchievedHardcore": 0
},
"1838": {
"NumPossibleAchievements": "48",
"PossibleScore": "400",
"NumAchieved": "48",
"ScoreAchieved": "400",
"NumAchievedHardcore": "48",
"ScoreAchievedHardcore": "400"
},
"7634": {
"NumPossibleAchievements": 0,
"PossibleScore": 0,
"NumAchieved": 0,
"ScoreAchieved": 0,
"NumAchievedHardcore": 0,
"ScoreAchievedHardcore": 0
}
}

Teraz mam klasę, której chcę użyć do odpowiedzi

public class UserProgress {

private Map<String, Progress> userProgress;

public Map<String, Progress> getUserProgress() {
return userProgress;
}
}

Również klasa reprezentująca obiekt wewnętrzny na tej mapie

public class Progress {

@SerializedName("NumPossibleAchievements")
private String numPossibleAchievements;
@SerializedName("PossibleScore")
private String possibleScore;
@SerializedName("NumAchieved")
private int numAchieved;
@SerializedName("ScoreAchieved")
private int scoreAchieved;
@SerializedName("NumAchievedHardcore")
private int numAchievedHardcore;
@SerializedName("ScoreAchievedHardcore")
private int scoreAchievedHardcore;

.....

I niestandardowy deserializator, który powinien parsować ten typ JSON do normalnego obiektu. Ten deserializator dodałem do konwertera modernizacyjnego.

public class UserProgressDeserializer implements JsonDeserializer<UserProgress> {

@Override
public UserProgress deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final Map<String, Progress> parameters = readParametersMap(jsonObject);
final UserProgress result = new UserProgress();

if (parameters != null) result.setUserProgress(parameters);
return result;
}

@Nullable
private Map<String, Progress> readParametersMap(@NonNull final JsonObject jsonObject) {
final JsonElement paramsElement = jsonObject.getAsJsonObject();
if (paramsElement == null) return null;

final JsonObject parametersObject = paramsElement.getAsJsonObject();
final Map<String, Progress> parameters = new HashMap<>();
for (Map.Entry<String, JsonElement> entry : parametersObject.entrySet()) {
String key = entry.getKey();
Progress value = new Gson().fromJson(entry.getValue().getAsString(), Progress.class);
parameters.put(key, value);
}
return parameters;
}
}

I moja prośba

@GET("API_GetUserProgress.php")
Flowable<UserProgress> getUserProgress(@Query("u") @NonNull String userName,
@Query("i") String gamesCSV);

Żądaj pracy, w surowym ciele widzę, że JSON, aleobiekt zawiera pustą mapę. Testowałem z punktami przerwania, ale nigdy nie przechodzi do deserializatora. Teraz moim pomysłem jest stworzenie niestandardowej funkcji, która będzie parsować łańcuch JSON z surowego ciała odpowiedzi, ale to będzie skok.

Dzięki za pomoc

Odpowiedzi:

0 dla odpowiedzi № 1

UPD: Wygląda na to, że GSON akceptuje Mapa dla obiekty po wyjęciu z pudełka i rzucić te obiekty LinkedTreeMap. Potrzebowaliśmy tylko zmienić typ żądania zwrotu.

Flowable<Map<String, Progress>> getUserProgress(@Query("u") @NonNull String userName,
@Query("i") String gamesCSV);

ZBĘDNY

Nie odniosłem sukcesu z niestandardowym deserializatorem, więc zaimplementowałem nową funkcję, która akceptuje ciąg JSON surowa odpowiedź, wyniki map do listy wymaganych obiektów. A teraz wygląda

Flowable<ResponseBody> flowable = USERS_API.getUserProgress(userName, gameIDsCSV);
return manageRequestWithMapper(flowable, responseBody -> {
String body = responseBody.string();
JSONObject yourJSON = new JSONObject(body);
Iterator<String> keysIterator = yourJSON.keys();
List<Progress> tempList = new ArrayList<>();
while (keysIterator.hasNext()) {
String key = keysIterator.next();
JSONObject actualObj = (JSONObject) yourJSON.get(key);
tempList.add((new Gson()).fromJson(actualObj.toString(), Progress.class));
}
return tempList;
});