Java tutorial
/* * Copyright 2010-2013 Ning, Inc. * * Ning 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 com.ning.billing.recurly.model; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.annotation.Nullable; import javax.xml.bind.annotation.XmlTransient; import org.joda.time.DateTime; import com.ning.billing.recurly.RecurlyClient; import com.ning.billing.recurly.model.jackson.RecurlyObjectsSerializer; import com.ning.billing.recurly.model.jackson.RecurlyXmlSerializerProvider; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.joda.JodaModule; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; @JsonIgnoreProperties(ignoreUnknown = true) public abstract class RecurlyObject { @XmlTransient private RecurlyClient recurlyClient; @XmlTransient protected String href; public static final String NIL_STR = "nil"; public static final List<String> NIL_VAL = Arrays.asList("nil", "true"); // See https://github.com/killbilling/recurly-java-library/issues/4 for why // @JsonIgnore is required here and @XmlTransient is not enough @JsonIgnore public String getHref() { return href; } public void setHref(final Object href) { this.href = stringOrNull(href); } public static XmlMapper newXmlMapper() { final XmlMapper xmlMapper = new XmlMapper(); xmlMapper.setSerializerProvider(new RecurlyXmlSerializerProvider()); final AnnotationIntrospector primary = new JacksonAnnotationIntrospector(); final AnnotationIntrospector secondary = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); final AnnotationIntrospector pair = new AnnotationIntrospectorPair(primary, secondary); xmlMapper.setAnnotationIntrospector(pair); xmlMapper.registerModule(new JodaModule()); xmlMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); final SimpleModule m = new SimpleModule("module", new Version(1, 0, 0, null, null, null)); m.addSerializer(Accounts.class, new RecurlyObjectsSerializer<Accounts, Account>(Accounts.class, "account")); m.addSerializer(AddOns.class, new RecurlyObjectsSerializer<AddOns, AddOn>(AddOns.class, "add_on")); m.addSerializer(Adjustments.class, new RecurlyObjectsSerializer<Adjustments, Adjustment>(Adjustments.class, "adjustment")); m.addSerializer(Coupons.class, new RecurlyObjectsSerializer<Coupons, Coupon>(Coupons.class, "coupon")); m.addSerializer(Invoices.class, new RecurlyObjectsSerializer<Invoices, Invoice>(Invoices.class, "invoice")); m.addSerializer(Plans.class, new RecurlyObjectsSerializer<Plans, Plan>(Plans.class, "plan")); m.addSerializer(RecurlyErrors.class, new RecurlyObjectsSerializer<RecurlyErrors, RecurlyError>(RecurlyErrors.class, "error")); m.addSerializer(SubscriptionAddOns.class, new RecurlyObjectsSerializer<SubscriptionAddOns, SubscriptionAddOn>(SubscriptionAddOns.class, "subscription_add_on")); m.addSerializer(Subscriptions.class, new RecurlyObjectsSerializer<Subscriptions, Subscription>(Subscriptions.class, "subscription")); m.addSerializer(Transactions.class, new RecurlyObjectsSerializer<Transactions, Transaction>(Transactions.class, "transaction")); xmlMapper.registerModule(m); return xmlMapper; } public static Boolean booleanOrNull(@Nullable final Object object) { if (isNull(object)) { return null; } // Booleans are represented as objects (e.g. <display_quantity type="boolean">false</display_quantity>), which Jackson // will interpret as an Object (Map), not Booleans. if (object instanceof Map) { final Map map = (Map) object; if (map.keySet().size() == 2 && "boolean".equals(map.get("type"))) { return Boolean.valueOf((String) map.get("")); } } return Boolean.valueOf(object.toString()); } public static String stringOrNull(@Nullable final Object object) { if (isNull(object)) { return null; } return object.toString().trim(); } public static Integer integerOrNull(@Nullable final Object object) { if (isNull(object)) { return null; } // Integers are represented as objects (e.g. <year type="integer">2015</year>), which Jackson // will interpret as an Object (Map), not Integers. if (object instanceof Map) { final Map map = (Map) object; if (map.keySet().size() == 2 && "integer".equals(map.get("type"))) { return Integer.valueOf((String) map.get("")); } } return Integer.valueOf(object.toString()); } public static DateTime dateTimeOrNull(@Nullable final Object object) { if (isNull(object)) { return null; } // DateTimes are represented as objects (e.g. <created_at type="datetime">2011-04-19T07:00:00Z</created_at>), which Jackson // will interpret as an Object (Map), not DateTimes. if (object instanceof Map) { final Map map = (Map) object; if (map.keySet().size() == 2 && "datetime".equals(map.get("type"))) { return new DateTime(map.get("")); } } return new DateTime(object.toString()); } public static boolean isNull(@Nullable final Object object) { if (object == null) { return true; } // Hack to work around Recurly output for nil values: the response will contain // an element with a nil attribute (e.g. <city nil="nil"></city> or <username nil="true"></username>) which Jackson will // interpret as an Object (Map), not a String. if (object instanceof Map) { final Map map = (Map) object; if (map.keySet().size() >= 1 && map.get(NIL_STR) != null && NIL_VAL.contains(map.get(NIL_STR).toString())) { return true; } } return false; } <T extends RecurlyObject> T fetch(final T object, final Class<T> clazz) { if (object.getHref() == null || recurlyClient == null) { return object; } return recurlyClient.doGETWithFullURL(clazz, object.getHref()); } public void setRecurlyClient(final RecurlyClient recurlyClient) { this.recurlyClient = recurlyClient; } }