com.ikanow.infinit.e.data_model.api.BaseApiPojo.java Source code

Java tutorial

Introduction

Here is the source code for com.ikanow.infinit.e.data_model.api.BaseApiPojo.java

Source

/*******************************************************************************
 * Copyright 2012 The Infinit.e Open Source Project
 * 
 * Licensed 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.ikanow.infinit.e.data_model.api;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.bson.types.ObjectId;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;
import com.ikanow.infinit.e.data_model.utils.ThreadSafeSimpleDateFormat;

public class BaseApiPojo {
    // Every Pojo should "override" this static function (stick the actual class in the 2x <>s) for readability
    static public <S> TypeToken<List<S>> listType() {
        return new TypeToken<List<S>>() {
        };
    }

    // Override this function to perform custom serialization (see BasePojoApiMap)
    public GsonBuilder extendBuilder(GsonBuilder gp) {
        return extendBuilder_internal(gp);
    }

    // Allows API owner to enforce some custom serializations
    final public static GsonBuilder getDefaultBuilder() {
        GsonBuilder gb = new GsonBuilder().registerTypeAdapter(ObjectId.class, new ObjectIdSerializer())
                .registerTypeAdapter(ObjectId.class, new ObjectIdDeserializer())
                .registerTypeAdapter(Date.class, new DateDeserializer())
                .registerTypeAdapter(Date.class, new DateSerializer())
                .registerTypeAdapter(JsonArray.class, new JsonArraySerializer());
        return gb;
    }

    private static GsonBuilder extendBuilder_internal(GsonBuilder gp) {
        return gp;
    }
    //________________________________________________________________________________________________

    // Won't normally override these (but can)
    // DB format conversion

    // For BaseApiPojos
    // 2 versions, 1 where you need dynamic mapping (eg runtime-specific)
    // (in both cases for single objects, you can use the nicer class<X> or 
    //  the nastier Google TypeToken, the latter has 2 advantages:
    //  a. consisntency with list types, where you have to use the TypeToken
    //  b. the class<X> doesn't work where X is generic)
    //
    // Note - the code is a bit unpleastant in places....

    /////////////////////////////////////////////////////////////////////////////////////
    // To the API JSON From a single Object
    public static <S extends BaseApiPojo> String toApi(S s) {
        return toApi(s, null);
    }

    // (Nicer version of the static "toApi")   
    public String toApi() {
        return toApi(this);
    }

    public static <S extends BaseApiPojo> String toApi(S s, BasePojoApiMap<S> dynamicMap) {
        GsonBuilder gb = s.extendBuilder(BaseApiPojo.getDefaultBuilder());
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return gb.create().toJson(s);
    }

    /////////////////////////////////////////////////////////////////////////////////////
    // From the API JSON To a single Object
    public static <S extends BaseApiPojo> S fromApi(String s, Class<S> type) {
        return fromApi(s, type, null);
    }

    public static <S extends BaseApiPojo> S fromApi(JsonElement j, Class<S> type) {
        return fromApi(j, type, null);
    }

    public static <S extends BaseApiPojo> S fromApi(String s, TypeToken<S> type) {
        return fromApi(s, type, null);
    }

    public static <S extends BaseApiPojo> S fromApi(JsonElement j, TypeToken<S> type) {
        return fromApi(j, type, null);
    }

    public static <S extends BaseApiPojo> S fromApi(String s, Class<S> type, BasePojoApiMap<S> dynamicMap) {
        // Create a new instance of the class in order to override it
        GsonBuilder gb = null;
        try {
            gb = type.newInstance().extendBuilder(BaseApiPojo.getDefaultBuilder());
        } catch (Exception e) {
            return null;
        }
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return gb.create().fromJson(s.toString(), type);
    }

    public static <S extends BaseApiPojo> S fromApi(JsonElement j, Class<S> type, BasePojoApiMap<S> dynamicMap) {
        // Create a new instance of the class in order to override it
        GsonBuilder gb = null;
        try {
            gb = type.newInstance().extendBuilder(BaseApiPojo.getDefaultBuilder());
        } catch (Exception e) {
            return null;
        }
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return gb.create().fromJson(j, type);
    }

    @SuppressWarnings("unchecked")
    public static <S extends BaseApiPojo> S fromApi(String s, TypeToken<S> type, BasePojoApiMap<S> dynamicMap) {
        GsonBuilder gb = null;
        try {
            Class<S> clazz = (Class<S>) type.getType();
            gb = ((S) clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
        } catch (Exception e) {
            return null;
        }
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return (S) gb.create().fromJson(s.toString(), type.getType());
    }

    @SuppressWarnings("unchecked")
    public static <S extends BaseApiPojo> S fromApi(JsonElement j, TypeToken<S> type,
            BasePojoApiMap<S> dynamicMap) {
        GsonBuilder gb = null;
        try {
            Class<S> clazz = (Class<S>) type.getType();
            gb = ((S) clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
        } catch (Exception e) {
            return null;
        }
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return (S) gb.create().fromJson(j, type.getType());
    }

    /////////////////////////////////////////////////////////////////////////////////////
    // To the API JSON From a list of objects
    public static <S extends BaseApiPojo> String listToApi(Collection<S> list,
            TypeToken<? extends Collection<S>> listType) {
        return listToApi(list, listType, null);
    }

    public static <S extends BaseApiPojo> String listToApi(Collection<S> list,
            TypeToken<? extends Collection<S>> listType, BasePojoApiMap<S> dynamicMap) {
        GsonBuilder gb = null;
        try {
            if (!list.isEmpty()) {
                gb = list.iterator().next().extendBuilder(BaseApiPojo.getDefaultBuilder());
            }
        } catch (Exception e) {
            return null;
        }
        return gb.create().toJson(list, listType.getType());
    }

    /////////////////////////////////////////////////////////////////////////////////////
    // From the API JSON to a list of objects
    public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(String json,
            TypeToken<? extends L> listType) {
        return listFromApi(json, listType, null);
    }

    public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(JsonElement json,
            TypeToken<? extends L> listType) {
        return listFromApi(json, listType, null);
    }

    @SuppressWarnings("unchecked")
    public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(String json,
            TypeToken<? extends L> listType, BasePojoApiMap<S> dynamicMap) {
        GsonBuilder gb = null;
        try {
            Class<S> clazz = (Class<S>) ((ParameterizedType) listType.getType()).getActualTypeArguments()[0];
            // (know this works because of construction of listType)
            gb = (clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
        } catch (Exception e) {
            return null;
        }
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return (L) gb.create().fromJson(json, listType.getType());
    }

    @SuppressWarnings("unchecked")
    public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(JsonElement json,
            TypeToken<? extends L> listType, BasePojoApiMap<S> dynamicMap) {
        GsonBuilder gb = null;
        try {
            Class<S> clazz = (Class<S>) ((ParameterizedType) listType.getType()).getActualTypeArguments()[0];
            // (know this works because of construction of listType)
            gb = (clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
        } catch (Exception e) {
            return null;
        }
        if (null != dynamicMap) {
            gb = dynamicMap.extendBuilder(gb);
        }
        return (L) gb.create().fromJson(json, listType.getType());
    }
    //___________________________________________________________________

    // Default MongoDB serialization rule:   
    // 1. Object Ids
    protected static class ObjectIdSerializer implements JsonSerializer<ObjectId> {
        @Override
        public JsonElement serialize(ObjectId id, Type typeOfT, JsonSerializationContext context) {
            return new JsonPrimitive(id.toStringMongod());
        }
    }

    protected static class ObjectIdDeserializer implements JsonDeserializer<ObjectId> {
        @Override
        public ObjectId deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                throws JsonParseException {
            if (json.isJsonPrimitive()) {
                return new ObjectId(json.getAsString());
            } else {
                try {
                    return new ObjectId(json.getAsJsonObject().get("$oid").getAsString());
                } catch (Exception e) {
                    return null;
                }
            }
        }
    }

    protected static class DateDeserializer implements JsonDeserializer<Date> {
        private static ThreadSafeSimpleDateFormat _format = new ThreadSafeSimpleDateFormat(
                "yyyy-MM-dd'T'HH:mm:ss'Z'");
        private static ThreadSafeSimpleDateFormat _format2 = new ThreadSafeSimpleDateFormat(
                "MMM d, yyyy hh:mm:ss a");

        @Override
        public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                throws JsonParseException {
            Date d = null;
            try {
                d = _format2.parse(json.getAsString());
            } catch (Exception e) {
                try {
                    d = _format.parse(json.getAsString());
                } catch (Exception e2) {
                    d = null;
                }
            }
            return d;
        }
    }

    // Just convert API calls to UTC
    protected static class DateSerializer implements JsonSerializer<Date> {
        @Override
        public JsonElement serialize(Date date, Type typeOfT, JsonSerializationContext context) {
            ThreadSafeSimpleDateFormat tsdf = new ThreadSafeSimpleDateFormat("MMM d, yyyy hh:mm:ss a 'UTC'");
            return new JsonPrimitive(tsdf.format(date));
        }
    }

    protected static class JsonArraySerializer implements JsonSerializer<JsonArray> {
        @Override
        public JsonElement serialize(JsonArray jsonArray, Type typeOfT, JsonSerializationContext context) {
            return jsonArray;
        }
    }
}