Reputation: 2976
I have the following JSON file:
EDIT: In case the above link does not work: https://pastebin.com/cTxp1RZ6
Now the only possibility I have found so far to fetch this JSON is using a Map:
Call<Map<String, Object>> call = liveApi.loadProductList(request.categoryId, request.sort, request.lazyLoading)
call.enqueue(new Callback<Map<String, Object>>() {
@Override
public void onResponse(Call<Map<String, Object>> call, Response<Map<String, Object>> response) {
Call<Map<String, Object> map = response.body();
}
});
But then I need to find all objects within the lower layers by keys. I would love to map those objects to my model classes with @SerializedName()
, How could I do that?
Upvotes: 1
Views: 1575
Reputation: 21115
All you have to do is creating custom mappings. Since your JSON document is pretty complex, you can try automatic mapping generators, but if they fail for any reason (dynamic properties, polymorphic values, improper camelCaseNaming detection, etc), you can always create your custom mappings:
final class Response {
@SerializedName("categories") final List<Category> categories = null;
@SerializedName("facettes") final List<Facet> facettes = null;
@SerializedName("productlistentries") final List<Map<String, Product>> productListEntries = null;
@SerializedName("last") final boolean isLast = Boolean.valueOf(false);
}
final class Category {
@SerializedName("amount") final int amount = Integer.valueOf(0);
}
final class Facet {
// ???
}
final class Product {
@SerializedName("name") final String name = null;
@SerializedName("modelNumber") final int modelNumber = Integer.valueOf(0);
@SerializedName("brandLogo") final String brandLogo = null;
@SerializedName("detailLink") final String detailLink = null;
@SerializedName("online") final boolean isOnline = Boolean.valueOf(false);
@SerializedName("imageURL") final String imageUrl = null;
@SerializedName("addToBasketUrl") final String addToBasketUrl = null;
@SerializedName("rating") final int rating = Integer.valueOf(0);
@SerializedName("ratingCount") final int ratingCount = Integer.valueOf(0);
@SerializedName("features") final List<Feature> features = null;
@SerializedName("price") final String price = null;
@SerializedName("vatLabel") final String vatLabel = null;
@SerializedName("fees") final List<Fee> fees = null;
@SerializedName("gtm") final Gtm gtm = null;
@SerializedName("productComparison") final ProductComparison productComparison = null;
@SerializedName("productWishlist") final ProductWishlist productWishlist = null;
@SerializedName("clubProduct") final boolean isClubProduct = Boolean.valueOf(false);
@SerializedName("onlineOnlyProduct") final boolean isOnlineOnlyProduct = Boolean.valueOf(false);
}
final class Feature {
@SerializedName("key") final String key = null;
@SerializedName("value") final String value = null;
}
final class Fee {
@SerializedName("value") final String value = null;
@SerializedName("dataLayer") final String dataLayer = null;
}
final class Gtm {
@SerializedName("name") final String name = null;
@SerializedName("id") final String id = null;
@SerializedName("price") final String price = null;
@SerializedName("brand") final String brand = null;
@SerializedName("category") final String category = null;
@SerializedName("dimension9") final String dimension9 = null;
@SerializedName("dimension10") final String dimension10 = null;
}
final class ProductComparison {
@SerializedName("dataLayer") final String dataLayer = null;
@SerializedName("dataUrl") final String dataUrl = null;
@SerializedName("text") final String text = null;
@SerializedName("additionalClasses") final String additionalClasses = null;
}
final class ProductWishlist {
@SerializedName("requestUrl") final String requestUrl = null;
@SerializedName("text") final String text = null;
}
It took about 15 minutes to write the mappings by hand, so they might have mistakes or typos. Note that I'm assuming your response is read-only and not supposed to be created manually to be sent elsewhere, so all of fields are declared final
. One remark regarding the primitive fields: if you use 0
or false
, then Java compiler can inline known-at-compile-time constants, so Type.value(...)
is a sort of cheating to let javac think it's a runtime value that cannot be inlined. (You might want to generate getters, but IMHO fields for simple databags are easier to use and add less noise).
All you have to do is changing Call<Map<String, Object>>
to Call<Response>
.
Example in vanilla Java, not Retrofit:
try ( final Reader reader = getPackageResourceReader(Q43535942.class, "response.json") ) {
final Response response = gson.fromJson(reader, Response.class);
System.out.println(response.productListEntries.get(1).get("3486143").imageUrl);
}
Output:
//picscdn.redblue.de/doi/pixelboxx-mss-70874441/mobile_220_310_png/CRUNCH-GTO-4125-Verst%C3%A4rker-%28Class-D%29
Upvotes: 2