org.droidparts.inner.converter.ArrayCollectionConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.droidparts.inner.converter.ArrayCollectionConverter.java

Source

/**
 * Copyright 2015 Alex Yanchenko
 * 
 * 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 org.droidparts.inner.converter;

import static org.droidparts.inner.ReflectionUtils.newInstance;
import static org.droidparts.inner.TypeHelper.isArray;
import static org.droidparts.inner.TypeHelper.isModel;
import static org.droidparts.util.Strings.isNotEmpty;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.droidparts.inner.ConverterRegistry;
import org.droidparts.inner.PersistUtils;
import org.droidparts.inner.TypeHelper;
import org.droidparts.model.Model;
import org.droidparts.util.Arrays2;
import org.droidparts.util.Strings;
import org.json.JSONArray;
import org.json.JSONObject;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.content.ContentValues;
import android.database.Cursor;

public class ArrayCollectionConverter extends Converter<Object> {

    // ASCII RS (record separator), '|' for readability
    private static final String SEP = "|" + (char) 30;

    @Override
    public boolean canHandle(Class<?> cls) {
        return TypeHelper.isArray(cls) || TypeHelper.isCollection(cls);
    }

    @Override
    public String getDBColumnType() {
        return BLOB;
    }

    @Override
    public <G1, G2> Object readFromJSON(Class<Object> valType, Class<G1> genericArg1, Class<G2> genericArg2,
            JSONObject obj, String key) throws Exception {
        Converter<JSONArray> conv = ConverterRegistry.getConverter(JSONArray.class);
        Wrapper w = new Wrapper(conv.readFromJSON(JSONArray.class, null, null, obj, key), null);
        return readFromWrapper(valType, genericArg1, w);
    }

    @Override
    public <G1, G2> Object readFromXML(Class<Object> valType, Class<G1> genericArg1, Class<G2> genericArg2,
            Node node, String nodeListItemTagHint) throws Exception {
        NodeList nl = node.getChildNodes();
        ArrayList<Node> elementNodes = new ArrayList<Node>();
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i);
            if (n.getNodeType() == Node.ELEMENT_NODE) {
                if (isNotEmpty(nodeListItemTagHint)) {
                    if (nodeListItemTagHint.equals(n.getNodeName())) {
                        elementNodes.add(n);
                    }
                } else {
                    elementNodes.add(n);
                }
            }
        }
        Wrapper w = new Wrapper(null, elementNodes);
        return readFromWrapper(valType, genericArg1, w);
    }

    @Override
    public <G1, G2> void putToJSON(Class<Object> valType, Class<G1> genericArg1, Class<G2> genericArg2,
            JSONObject obj, String key, Object val) throws Exception {
        Converter<G1> converter = ConverterRegistry.getConverter(genericArg1);
        ArrayList<G1> list = arrOrCollToList(valType, genericArg1, val);
        JSONArray vals = new JSONArray();
        JSONObject tmpObj = new JSONObject();
        for (G1 value : list) {
            converter.putToJSON(genericArg1, null, null, tmpObj, "key", value);
            vals.put(tmpObj.get("key"));
        }
        obj.put(key, vals);
    }

    //
    @SuppressWarnings("unchecked")
    protected <V> Object readFromWrapper(Class<Object> valType, Class<V> genericArg1, Wrapper wrapper)
            throws Exception {
        boolean isArr = isArray(valType);
        boolean isModel = isModel(genericArg1);
        Collection<Object> items;
        if (isArr) {
            items = new ArrayList<Object>();
        } else {
            items = (Collection<Object>) newInstance(valType);
        }
        Converter<V> converter = ConverterRegistry.getConverter(genericArg1);
        for (int i = 0; i < wrapper.size(); i++) {
            Object item = wrapper.get(i);
            if (isModel) {
                item = wrapper.deserialize(item, converter, genericArg1);
            } else {
                item = wrapper.convert(item, converter, genericArg1);
            }
            items.add(item);
        }
        if (isArr) {
            Object[] arr = items.toArray();
            if (isModel) {
                Object modelArr = Array.newInstance(genericArg1, arr.length);
                for (int i = 0; i < arr.length; i++) {
                    Array.set(modelArr, i, arr[i]);
                }
                return modelArr;
            } else {
                String[] arr2 = new String[arr.length];
                for (int i = 0; i < arr.length; i++) {
                    arr2[i] = arr[i].toString();
                }
                return parseTypeArr(converter, genericArg1, arr2);
            }
        } else {
            return items;
        }
    }

    @Override
    public <G1, G2> void putToContentValues(Class<Object> valueType, Class<G1> genericArg1, Class<G2> genericArg2,
            ContentValues cv, String key, Object val) throws Exception {
        Converter<G1> converter = ConverterRegistry.getConverter(genericArg1);
        if (converter.getDBColumnType() == BLOB) {
            byte[] bytes = PersistUtils.toBytes(val);
            cv.put(key, bytes);
        } else {
            ArrayList<G1> list = arrOrCollToList(valueType, genericArg1, val);
            ArrayList<Object> vals = new ArrayList<Object>();
            ContentValues tmpCV = new ContentValues();
            for (G1 obj : list) {
                converter.putToContentValues(genericArg1, null, null, tmpCV, "key", obj);
                vals.add(tmpCV.get("key"));
            }
            String strVal = Strings.join(vals, SEP);
            cv.put(key, strVal);
        }
    }

    @Override
    public <G1, G2> Object readFromCursor(Class<Object> valType, Class<G1> genericArg1, Class<G2> genericArg2,
            Cursor cursor, int columnIndex) throws Exception {
        Converter<G1> converter = ConverterRegistry.getConverter(genericArg1);
        if (converter.getDBColumnType() == BLOB) {
            byte[] arr = cursor.getBlob(columnIndex);
            return (arr != null) ? PersistUtils.fromBytes(arr) : null;
        } else {
            String str = cursor.getString(columnIndex);
            String[] parts = (str.length() > 0) ? str.split("\\" + SEP) : new String[0];
            if (isArray(valType)) {
                return parseTypeArr(converter, genericArg1, parts);
            } else {
                return parseTypeColl(converter, valType, genericArg1, parts);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private <T> ArrayList<T> arrOrCollToList(Class<?> valType, Class<T> genericArg1, Object val) {
        ArrayList<T> list = new ArrayList<T>();
        if (isArray(valType)) {
            list.addAll((List<T>) Arrays.asList(Arrays2.toObjectArray(val)));
        } else {
            list.addAll((Collection<T>) val);
        }
        return list;
    }

    // say hello to arrays of primitives
    private final <T> Object parseTypeArr(Converter<T> converter, Class<T> valType, String[] arr) throws Exception {
        Object objArr = Array.newInstance(valType, arr.length);
        for (int i = 0; i < arr.length; i++) {
            T item = converter.parseFromString(valType, null, null, arr[i]);
            Array.set(objArr, i, item);
        }
        return objArr;
    }

    private final <T> Collection<T> parseTypeColl(Converter<T> converter, Class<Object> collType,
            Class<T> genericArg1, String[] arr) throws Exception {
        @SuppressWarnings("unchecked")
        Collection<T> coll = (Collection<T>) newInstance(collType);
        for (int i = 0; i < arr.length; i++) {
            T item = converter.parseFromString(genericArg1, null, null, arr[i]);
            coll.add(item);
        }
        return coll;
    }

    //

    private static class Wrapper {
        private final JSONArray arr;
        private final ArrayList<Node> nodes;

        private final JSONObject tmp = new JSONObject();

        Wrapper(JSONArray arr, ArrayList<Node> nodes) {
            this.arr = arr;
            this.nodes = nodes;
        }

        int size() {
            return isJSON() ? arr.length() : nodes.size();
        }

        <V> Object get(int i) throws Exception {
            if (isJSON()) {
                return arr.get(i);
            } else {
                return nodes.get(i);
            }
        }

        <V> Object convert(Object item, Converter<V> conv, Class<V> valType) throws Exception {
            if (isJSON()) {
                if (item.getClass() == valType) {
                    return item;
                } else {
                    tmp.put("key", item);
                    return conv.readFromJSON(valType, null, null, tmp, "key");
                }
            } else {
                String txt = PersistUtils.getNodeText((Node) item);
                return conv.parseFromString(valType, null, null, txt);
            }
        }

        @SuppressWarnings("unchecked")
        <V, M extends Model> Object deserialize(Object item, Converter<V> conv, Class<V> valType) throws Exception {
            ModelConverter<M> mc = (ModelConverter<M>) conv;
            Class<M> cl = (Class<M>) valType;
            if (isJSON()) {
                JSONObject obj = (JSONObject) item;
                return mc.getJSONSerializer(cl, obj).deserialize(obj);
            } else {
                Node node = (Node) item;
                return mc.getXMLSerializer(cl, node).deserialize(node);
            }
        }

        private boolean isJSON() {
            return (arr != null);
        }

    }

}