All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.droidparts.inner.converter.ArrayCollectionConverter Maven / Gradle / Ivy

/**
 * Copyright 2014 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.persist.serializer.AbstractSerializer;
import org.droidparts.persist.serializer.JSONSerializer;
import org.droidparts.persist.serializer.XMLSerializer;
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 {

	// 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 TEXT;
	}

	@Override
	public  Object readFromJSON(Class valType,
			Class componentType, JSONObject obj, String key)
			throws Exception {
		Wrapper w = new Wrapper(obj.getJSONArray(key), null);
		return readFromWrapper(valType, componentType, w);
	}

	@Override
	public  Object readFromXML(Class valType,
			Class componentType, Node node, String nodeListItemTagHint)
			throws Exception {
		NodeList nl = node.getChildNodes();
		ArrayList elementNodes = new ArrayList();
		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, componentType, w);
	}

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

	@Override
	protected  Object parseFromString(Class valType,
			Class componentType, String str) {
		throw new UnsupportedOperationException();
	}

	//
	@SuppressWarnings("unchecked")
	protected  Object readFromWrapper(Class valType,
			Class componentType, Wrapper wrapper) throws Exception {
		boolean isArr = isArray(valType);
		boolean isModel = isModel(componentType);
		Collection items;
		if (isArr) {
			items = new ArrayList();
		} else {
			items = (Collection) newInstance(valType);
		}
		AbstractSerializer serializer = null;
		if (isModel) {
			serializer = (AbstractSerializer) wrapper
					.makeSerializer((Class) componentType);
		}
		Converter converter = ConverterRegistry.getConverter(componentType);
		for (int i = 0; i < wrapper.size(); i++) {
			Object item = wrapper.get(i);
			if (isModel) {
				item = serializer.deserialize(item);
			} else {
				item = wrapper.convert(item, converter, componentType);
			}
			items.add(item);
		}
		if (isArr) {
			Object[] arr = items.toArray();
			if (isModel) {
				Object modelArr = Array.newInstance(componentType, 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, componentType, arr2);
			}
		} else {
			return items;
		}
	}

	@Override
	public  void putToContentValues(Class valueType,
			Class componentType, ContentValues cv, String key, Object val)
			throws Exception {
		Converter converter = ConverterRegistry.getConverter(componentType);
		ArrayList list = arrOrCollToList(valueType, componentType, val);
		ArrayList vals = new ArrayList();
		ContentValues tmpCV = new ContentValues();
		for (V obj : list) {
			converter
					.putToContentValues(componentType, null, tmpCV, "key", obj);
			vals.add(tmpCV.get("key"));
		}
		String strVal = Strings.join(vals, SEP);
		cv.put(key, strVal);
	}

	@Override
	public  Object readFromCursor(Class valType,
			Class componentType, Cursor cursor, int columnIndex)
			throws Exception {
		Converter converter = ConverterRegistry.getConverter(componentType);
		String str = cursor.getString(columnIndex);
		String[] parts = (str.length() > 0) ? str.split("\\" + SEP)
				: new String[0];
		if (isArray(valType)) {
			return parseTypeArr(converter, componentType, parts);
		} else {
			return parseTypeColl(converter, valType, componentType, parts);
		}
	}

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

	// say hello to arrays of primitives
	private final  Object parseTypeArr(Converter converter,
			Class 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, arr[i]);
			Array.set(objArr, i, item);
		}
		return objArr;
	}

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

	//

	private static class Wrapper {
		private final JSONArray arr;
		private final ArrayList nodes;

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

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

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

		 Object convert(Object item, Converter conv, Class valType)
				throws Exception {
			if (isJSON()) {
				return item;
			} else {
				Node n = (Node) item;
				String txt = PersistUtils.getNodeText(n);
				return conv.parseFromString(valType, null, txt);
			}
		}

		 AbstractSerializer makeSerializer(
				Class componentType) {
			if (isJSON()) {
				return new JSONSerializer(componentType, null);
			} else {
				return new XMLSerializer(componentType, null);
			}
		}

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

	}

}