killbill-memoizeit

Merge pull request #440 from maguero/ma-issue-158 Retrieve

12/1/2015 10:36:14 PM

Details

diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index 975d9eb..3841905 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -48,7 +48,6 @@ import org.killbill.billing.catalog.api.PlanAlignmentChange;
 import org.killbill.billing.catalog.api.PlanAlignmentCreate;
 import org.killbill.billing.catalog.api.PlanChangeResult;
 import org.killbill.billing.catalog.api.PlanPhase;
-import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.PlanSpecifier;
@@ -254,6 +253,10 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
         return versionForDate(requestedDate).getCurrentPlans();
     }
 
+    public DefaultPriceListSet getPriceLists(final DateTime requestedDate) throws CatalogApiException {
+        return versionForDate(requestedDate).getStandaloneCatalog().getPriceLists();
+    }
+
     //
     // Find a plan
     //
@@ -397,6 +400,10 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
         return versionForDate(clock.getUTCNow()).getEffectiveDate();
     }
 
+    public Date getEffectiveDate(final DateTime requestedDate) throws CatalogApiException {
+        return versionForDate(requestedDate).getEffectiveDate();
+    }
+
     @Override
     public BillingMode getRecurringBillingMode() {
         return recurringBillingMode;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
new file mode 100644
index 0000000..44eef61
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.jaxrs.json;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.catalog.DefaultPriceListSet;
+import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.CurrencyValueNull;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.Price;
+import org.killbill.billing.catalog.api.PriceList;
+import org.killbill.billing.catalog.api.Product;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class CatalogJson {
+
+    private final String name;
+    private final Date effectiveDate;
+    private final List<Currency> currencies;
+    private final List<ProductJson> products;
+    private final List<PriceListJson> priceLists;
+
+    @JsonCreator
+    public CatalogJson(@JsonProperty("name") final String name,
+                       @JsonProperty("effectiveDate") final Date effectiveDate,
+                       @JsonProperty("currencies") final List<Currency> currencies,
+                       @JsonProperty("products") final List<ProductJson> products,
+                       @JsonProperty("priceLists") final List<PriceListJson> priceLists) {
+        this.name = name;
+        this.effectiveDate = effectiveDate;
+        this.currencies = currencies;
+        this.products = products;
+        this.priceLists = priceLists;
+    }
+
+
+    public CatalogJson(final VersionedCatalog catalog, final DateTime requestedDate) throws CatalogApiException {
+        name = catalog.getCatalogName();
+        effectiveDate = catalog.getEffectiveDate(requestedDate);
+        currencies = Arrays.asList(catalog.getSupportedCurrencies(requestedDate));
+        priceLists = new ArrayList<PriceListJson>();
+
+        final Plan[] plans = catalog.getPlans(requestedDate);
+        final Map<String, ProductJson> productMap = new HashMap<String, ProductJson>();
+        for (final Plan plan : plans) {
+            // Build the product associated with this plan
+            final Product product = plan.getProduct();
+            ProductJson productJson = productMap.get(product.getName());
+            if (productJson == null) {
+                productJson = new ProductJson(product.getCategory().toString(),
+                                              product.getName(),
+                                              toProductNames(product.getIncluded()),
+                                              toProductNames(product.getAvailable()));
+                productMap.put(product.getName(), productJson);
+            }
+
+            // Build the phases associated with this plan
+            final List<PhaseJson> phases = new LinkedList<PhaseJson>();
+            for (final PlanPhase phase : plan.getAllPhases()) {
+                final List<PriceJson> prices = new LinkedList<PriceJson>();
+                if (phase.getRecurring() != null && phase.getRecurring().getRecurringPrice() != null) {
+                    for (final Price price : phase.getRecurring().getRecurringPrice().getPrices()) {
+                        prices.add(new PriceJson(price));
+                    }
+                }
+
+                final PhaseJson phaseJson = new PhaseJson(phase.getPhaseType().toString(), prices);
+                phases.add(phaseJson);
+            }
+
+            final PlanJson planJson = new PlanJson(plan.getName(), plan.getRecurringBillingPeriod(), phases);
+            productJson.getPlans().add(planJson);
+        }
+
+        products = ImmutableList.<ProductJson>copyOf(productMap.values());
+
+        final DefaultPriceListSet priceLists = catalog.getPriceLists(requestedDate);
+        for (PriceList childPriceList : priceLists.getAllPriceLists()) {
+            this.priceLists.add(new PriceListJson(childPriceList));
+        }
+
+    }
+
+    private List<String> toProductNames(final Product[] in) {
+        return Lists.transform(ImmutableList.<Product>copyOf(in),
+                               new Function<Product, String>() {
+                                   @Override
+                                   public String apply(final Product input) {
+                                       return input.getName();
+                                   }
+                               });
+    }
+
+    public List<ProductJson> getProducts() {
+        return products;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Date getEffectiveDate() {
+        return effectiveDate;
+    }
+
+    public List<Currency> getCurrencies() {
+        return currencies;
+    }
+
+    public List<PriceListJson> getPriceLists() {
+        return priceLists;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("CatalogJson{");
+        sb.append("name='").append(name).append('\'');
+        sb.append(", effectiveDate='").append(effectiveDate).append('\'');
+        sb.append(", currencies='").append(currencies).append('\'');
+        sb.append(", products=").append(products);
+        sb.append(", priceLists=").append(priceLists);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final CatalogJson that = (CatalogJson) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
+        if (effectiveDate != null ? !effectiveDate.equals(that.effectiveDate) : that.effectiveDate != null) {
+            return false;
+        }
+        if (currencies != null ? !currencies.equals(that.currencies) : that.currencies != null) {
+            return false;
+        }
+        if (products != null ? !products.equals(that.products) : that.products != null) {
+            return false;
+        }
+        if (priceLists != null ? !priceLists.equals(that.priceLists) : that.priceLists != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
+        result = 31 * result + (currencies != null ? currencies.hashCode() : 0);
+        result = 31 * result + (products != null ? products.hashCode() : 0);
+        return result;
+    }
+
+    public static class ProductJson {
+
+        private final String type;
+        private final String name;
+        private final List<PlanJson> plans;
+        private final List<String> included;
+        private final List<String> available;
+
+        @JsonCreator
+        public ProductJson(@JsonProperty("type") final String type,
+                           @JsonProperty("name") final String name,
+                           @JsonProperty("plans") final List<PlanJson> plans,
+                           @JsonProperty("included") final List<String> included,
+                           @JsonProperty("available") final List<String> available) {
+            this.type = type;
+            this.name = name;
+            this.plans = plans;
+            this.included = included;
+            this.available = available;
+        }
+
+        public ProductJson(final String type, final String name, final List<String> included, final List<String> available) {
+            this(type, name, new LinkedList<PlanJson>(), included, available);
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public List<PlanJson> getPlans() {
+            return plans;
+        }
+
+        public List<String> getIncluded() {
+            return included;
+        }
+
+        public List<String> getAvailable() {
+            return available;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("ProductJson{");
+            sb.append("type='").append(type).append('\'');
+            sb.append(", name='").append(name).append('\'');
+            sb.append(", plans=").append(plans);
+            sb.append(", included=").append(included);
+            sb.append(", available=").append(available);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final ProductJson that = (ProductJson) o;
+
+            if (available != null ? !available.equals(that.available) : that.available != null) {
+                return false;
+            }
+            if (included != null ? !included.equals(that.included) : that.included != null) {
+                return false;
+            }
+            if (name != null ? !name.equals(that.name) : that.name != null) {
+                return false;
+            }
+            if (plans != null ? !plans.equals(that.plans) : that.plans != null) {
+                return false;
+            }
+            if (type != null ? !type.equals(that.type) : that.type != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = type != null ? type.hashCode() : 0;
+            result = 31 * result + (name != null ? name.hashCode() : 0);
+            result = 31 * result + (plans != null ? plans.hashCode() : 0);
+            result = 31 * result + (included != null ? included.hashCode() : 0);
+            result = 31 * result + (available != null ? available.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public static class PlanJson {
+
+        private final String name;
+        private final BillingPeriod billingPeriod;
+        private final List<PhaseJson> phases;
+
+        @JsonCreator
+        public PlanJson(@JsonProperty("name") final String name,
+                        @JsonProperty("billingPeriod") final BillingPeriod billingPeriod,
+                        @JsonProperty("phases") final List<PhaseJson> phases) {
+            this.name = name;
+            this.billingPeriod = billingPeriod;
+            this.phases = phases;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public BillingPeriod getBillingPeriod() {
+            return billingPeriod;
+        }
+
+        public List<PhaseJson> getPhases() {
+            return phases;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PlanJson{");
+            sb.append("name='").append(name).append('\'');
+            sb.append("billingPeriod='").append(billingPeriod).append('\'');
+            sb.append(", phases=").append(phases);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PlanJson planJson = (PlanJson) o;
+
+            if (name != null ? !name.equals(planJson.name) : planJson.name != null) {
+                return false;
+            }
+            if (billingPeriod != null ? !billingPeriod.equals(planJson.billingPeriod) : planJson.billingPeriod != null) {
+                return false;
+            }
+            if (phases != null ? !phases.equals(planJson.phases) : planJson.phases != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name != null ? name.hashCode() : 0;
+            result = 31 * result + (billingPeriod != null ? billingPeriod.hashCode() : 0);
+            result = 31 * result + (phases != null ? phases.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public static class PhaseJson {
+
+        private final String type;
+        private final List<PriceJson> prices;
+
+        @JsonCreator
+        public PhaseJson(@JsonProperty("type") final String type,
+                         @JsonProperty("prices") final List<PriceJson> prices) {
+            this.type = type;
+            this.prices = prices;
+        }
+
+        public String getType() {
+            return type;
+        }
+        public List<PriceJson> getPrices() {
+            return prices;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PhaseJson{");
+            sb.append("type='").append(type).append('\'');
+            sb.append(", prices=").append(prices);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PhaseJson phaseJson = (PhaseJson) o;
+
+            if (prices != null ? !prices.equals(phaseJson.prices) : phaseJson.prices != null) {
+                return false;
+            }
+            if (type != null ? !type.equals(phaseJson.type) : phaseJson.type != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = type != null ? type.hashCode() : 0;
+            result = 31 * result + (prices != null ? prices.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public static class PriceJson {
+
+        private final String currency;
+        private final BigDecimal value;
+
+        @JsonCreator
+        public PriceJson(@JsonProperty("currency") final String currency,
+                         @JsonProperty("value") final BigDecimal value) {
+            this.currency = currency;
+            this.value = value;
+        }
+
+        public PriceJson(final Price price) throws CurrencyValueNull {
+            this(price.getCurrency().toString(), price.getValue());
+        }
+
+        public String getCurrency() {
+            return currency;
+        }
+
+        public BigDecimal getValue() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PriceJson{");
+            sb.append("currency='").append(currency).append('\'');
+            sb.append(", value=").append(value);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PriceJson priceJson = (PriceJson) o;
+
+            if (currency != null ? !currency.equals(priceJson.currency) : priceJson.currency != null) {
+                return false;
+            }
+            if (value != null ? !value.equals(priceJson.value) : priceJson.value != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = currency != null ? currency.hashCode() : 0;
+            result = 31 * result + (value != null ? value.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public static class PriceListJson {
+
+        private String name;
+        private List<String> plans;
+
+        @JsonCreator
+        public PriceListJson(@JsonProperty("name") final String name,
+                             @JsonProperty("plans") final List<String> plans) {
+            this.name = name;
+            this.plans = plans;
+        }
+
+        public PriceListJson(final PriceList priceList) {
+            this.name = priceList.getName();
+            List<String> plans = new ArrayList<String>();
+            for (Plan plan : priceList.getPlans()) {
+                plans.add(plan.getName());
+            }
+            this.plans = plans;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public List<String> getPlans() {
+            return plans;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("PriceListJson{");
+            sb.append("name='").append(name).append('\'');
+            sb.append(", plans=").append(plans);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final PriceListJson that = (PriceListJson) o;
+
+            if (name != null ? !name.equals(that.name) : that.name != null) {
+                return false;
+            }
+            return !(plans != null ? !plans.equals(that.plans) : that.plans != null);
+
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name != null ? name.hashCode() : 0;
+            result = 31 * result + (plans != null ? plans.hashCode() : 0);
+            return result;
+        }
+
+    }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
index bf5cc14..31e33a1 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
@@ -35,14 +35,17 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogUserApi;
 import org.killbill.billing.catalog.api.Listing;
 import org.killbill.billing.catalog.api.StaticCatalog;
-import org.killbill.billing.jaxrs.json.CatalogJsonSimple;
+import org.killbill.billing.jaxrs.json.CatalogJson;
 import org.killbill.billing.jaxrs.json.PlanDetailJson;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
@@ -123,12 +126,19 @@ public class CatalogResource extends JaxRsResourceBase {
     @TimedResource
     @GET
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve the full catalog as JSON", response = StaticCatalog.class)
+    @ApiOperation(value = "Retrieve the catalog as JSON", response = StaticCatalog.class)
     @ApiResponses(value = {})
-    public Response getCatalogJson(@javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
+    public Response getCatalogJson(@QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws Exception {
+        DateTime catalogDateVersion = clock.getUTCNow();
+        if (requestedDate != null) {
+            catalogDateVersion = DATE_TIME_FORMATTER.parseDateTime(requestedDate).toDateTime(DateTimeZone.UTC);
+        }
+
         final TenantContext tenantContext = context.createContext(request);
-        final StaticCatalog catalog = catalogUserApi.getCurrentCatalog(catalogName, tenantContext);
-        return Response.status(Status.OK).entity(catalog).build();
+        final Catalog catalog = catalogUserApi.getCatalog(catalogName, tenantContext);
+        final CatalogJson json = new CatalogJson((VersionedCatalog) catalog, catalogDateVersion);
+        return Response.status(Status.OK).entity(json).build();
     }
 
     // Need to figure out dependency on StandaloneCatalog
@@ -181,16 +191,4 @@ public class CatalogResource extends JaxRsResourceBase {
         return Response.status(Status.OK).entity(details).build();
     }
 
-    @TimedResource
-    @GET
-    @Path("/simpleCatalog")
-    @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a summarized version of the catalog as JSON", response = CatalogJsonSimple.class)
-    @ApiResponses(value = {})
-    public Response getSimpleCatalog(@javax.ws.rs.core.Context final HttpServletRequest request) throws CatalogApiException {
-        final TenantContext tenantContext = context.createContext(request);
-        final StaticCatalog catalog = catalogUserApi.getCurrentCatalog(catalogName, tenantContext);
-        final CatalogJsonSimple json = new CatalogJsonSimple(catalog);
-        return Response.status(Status.OK).entity(json).build();
-    }
 }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 68abf0c..fcc6476 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.67</version>
+        <version>0.68-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.15.10-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index 0d0608e..35a8890 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -18,16 +18,17 @@
 
 package org.killbill.billing.jaxrs;
 
+import java.sql.Date;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
+import org.joda.time.DateTime;
+import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.model.Catalog;
 import org.killbill.billing.client.model.Plan;
 import org.killbill.billing.client.model.PlanDetail;
 import org.killbill.billing.client.model.Product;
-import org.killbill.billing.util.jackson.ObjectMapper;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -44,33 +45,19 @@ public class TestCatalog extends TestJaxrsBase {
         Assert.assertNotNull(catalog);
     }
 
-    @Test(groups = "slow", description = "Can retrieve the full catalog as JSON, see https://github.com/killbill/killbill/issues/272")
-    public void testFullCatalogJSON() throws Exception {
-        final String jsonCatalog = killBillClient.getJSONCatalog();
-        // Verify we can serialize the StandaloneCatalog as JSON. While we usually never serialize
-        // directly API objects (we always transform them in the JAX-RS layer), this is a good
-        // regression test to make sure there are no loops and/or exceptions going through all
-        // the getters, which can be problematic in the Ruby bridge (see in particular
-        // https://github.com/killbill/killbill-java-parser/issues/6 and https://github.com/killbill/killbill-java-parser/issues/7).
-        // We don't attempt to de-serialize it back however because there is not enough information
-        // for Jackson (e.g. which concrete implementation of catalog objects to use). If we want to support
-        // this one day, we will need a translation layer in JAX-RS for all catalog objects.
-        final Map standaloneCatalog = new ObjectMapper().readValue(jsonCatalog, Map.class);
-        Assert.assertEquals(standaloneCatalog.get("catalogName"), "Firearms");
-        Assert.assertEquals(standaloneCatalog.get("recurringBillingMode"), "IN_ADVANCE");
-        Assert.assertEquals(standaloneCatalog.get("effectiveDate"), "2011-01-01T00:00:00.000+0000");
-        Assert.assertEquals(((List) standaloneCatalog.get("currentSupportedCurrencies")).size(), 3);
-        Assert.assertEquals(((List) standaloneCatalog.get("currentProducts")).size(), 11);
-        Assert.assertEquals(((List) standaloneCatalog.get("currentPlans")).size(), 20);
-        Assert.assertEquals(((List) standaloneCatalog.get("currentUnits")).size(), 1);
-    }
-
-    @Test(groups = "slow", description = "Can retrieve a simplified version of the catalog")
-    public void testCatalogSimple() throws Exception {
+    @Test(groups = "slow", description = "Can retrieve a json version of the catalog")
+    public void testCatalog() throws Exception {
         final Set<String> allBasePlans = new HashSet<String>();
 
-        final Catalog catalogJsonSimple = killBillClient.getSimpleCatalog();
-        for (final Product productJson : catalogJsonSimple.getProducts()) {
+        final Catalog catalogJson = killBillClient.getJSONCatalog();
+
+        Assert.assertEquals(catalogJson.getName(), "Firearms");
+        Assert.assertEquals(catalogJson.getEffectiveDate(), Date.valueOf("2011-01-01"));
+        Assert.assertEquals(catalogJson.getCurrencies().size(), 3);
+        Assert.assertEquals(catalogJson.getProducts().size(), 11);
+        Assert.assertEquals(catalogJson.getPriceLists().size(), 3);
+
+        for (final Product productJson : catalogJson.getProducts()) {
             if (!"BASE".equals(productJson.getType())) {
                 Assert.assertEquals(productJson.getIncluded().size(), 0);
                 Assert.assertEquals(productJson.getAvailable().size(), 0);
@@ -99,4 +86,13 @@ public class TestCatalog extends TestJaxrsBase {
         }
         Assert.assertEquals(foundBasePlans, allBasePlans);
     }
+
+    @Test(groups = "slow", description = "Try to retrieve a json version of the catalog with an invalid date",
+            expectedExceptions = KillBillClientException.class,
+            expectedExceptionsMessageRegExp = "There is no catalog version that applies for the given date.*")
+    public void testCatalogInvalidDate() throws Exception {
+        final Catalog catalogJson = killBillClient.getJSONCatalog(DateTime.parse("2008-01-01"));
+        Assert.fail();
+    }
+
 }