将Gson LinkedTreeMap改造为自定义对象

时间:2017-04-21 06:59:32

标签: json gson retrofit

我有以下JSON文件:

https://www.mediamarkt.de/de/product/productlistajax.json?categoryId=563612&sort=topseller&lazyLoading=true

编辑:如果上述链接不起作用:https://pastebin.com/cTxp1RZ6

现在我发现到目前为止获取此JSON的唯一可能是使用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();
    }
});

但是我需要通过键找到较低层内的所有对象。我很想用@SerializedName()将这些对象映射到我的模型类,我怎么能这样做?

1 个答案:

答案 0 :(得分:2)

您所要做的就是创建自定义映射。由于您的JSON文档非常复杂,您可以尝试自动映射生成器,但如果它们因任何原因失败(动态属性,多态值,不正确的camelCaseNaming检测等),您始终可以创建自定义映射:

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;

}

手动编写映射花了大约15分钟,因此可能会出现错误或拼写错误。请注意,我假设您的响应是只读的,不应该手动创建以便发送到其他地方,因此所有字段都声明为final。关于原始字段的一句话:如果你使用0false,那么Java编译器可以内联已知的编译时常量,所以Type.value(...)是一种让javac作弊的行为认为这是一个无法内联的运行时值。 (您可能希望生成getter,但是简单数据标签的IMHO字段更易于使用并且噪音更少)。

您所要做的就是将Call<Map<String, Object>>更改为Call<Response>

vanilla Java中的示例,而不是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);
}

输出:

  

// picscdn.redblue.de/doi/pixelboxx-mss-70874441/mobile_220_310_png/CRUNCH-GTO-4125-Verst%C3%A4rker-%28Class-D%29