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

com.threewks.thundr.csv.BeanToCsvStreamer Maven / Gradle / Ivy

The newest version!
/*
 * This file is a component of thundr, a software library from 3wks.
 * Read more: http://3wks.github.io/thundr/
 * Copyright (C) 2014 3wks, 
 *
 * 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.threewks.thundr.csv;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.opencsv.CSVWriter;
import com.opencsv.bean.BeanToCsv;
import com.opencsv.bean.MappingStrategy;
import com.threewks.thundr.exception.BaseException;
import com.threewks.thundr.transformer.TransformerManager;

/**
 * An implementation of BeanToCsv which can handle streaming results to minimise memory footprint.
 *
 * @param 
 */
public class BeanToCsvStreamer extends BeanToCsv {
	private static final int DefaultBatchSize = 1000;
	protected int batchSize;
	private TransformerManager transformerManager;

	public BeanToCsvStreamer(TransformerManager transformerManager) {
		this(transformerManager, DefaultBatchSize);
	}

	public BeanToCsvStreamer(TransformerManager transformerManager, int batchSize) {
		this.transformerManager = transformerManager;
		this.batchSize = Math.max(batchSize, 1);
	}

	public BeanToCsvStreamer withBatchSize(int batchSize) {
		this.batchSize = Math.max(batchSize, 1);
		return this;
	}

	public int getBatchSize() {
		return batchSize;
	}

	public boolean write(MappingStrategy mapper, CSVWriter csv, Iterable objects, boolean includeHeader) {
		if (objects == null) {
			return false;
		}
		Iterator iterator = objects.iterator();
		if (!iterator.hasNext()) {
			return false;
		}

		try {
			List getters = findGetters(mapper);
			if (includeHeader) {
				writeHeader(mapper, csv);
			}
			List batch = batch(iterator, batchSize);
			while (batch.size() > 0) {
				processAndWriteObjects(csv, batch, getters);
				batch = batch(iterator, batchSize);
			}
			return true;
		} catch (Exception e) {
			throw new RuntimeException("Error writing CSV !", e);
		}
	}

	public void writeHeader(MappingStrategy mapper, CSVWriter csv) {
		try {
			csv.writeNext(processHeader(mapper));
		} catch (Exception e) {
			throw new BaseException(e);
		}
	}

	public boolean write(MappingStrategy mapper, CSVWriter csv, Iterable objects) {
		return this.write(mapper, csv, objects, true);
	}

	private List batch(Iterator iterator, int size) {
		List batch = new ArrayList<>();
		for (int i = 0; i < size && iterator.hasNext(); i++) {
			batch.add(iterator.next());
		}
		return batch;
	}

	/**
	 * Build getters list from provided mapper.
	 * 
	 * @param mapper MappingStrategy for Bean
	 * @return - list of methods for getting the data in the bean.
	 * @throws IntrospectionException - thrown if there is an failure in Introspection.
	 */
	protected List findGetters(MappingStrategy mapper) throws IntrospectionException {
		int i = 0;
		PropertyDescriptor prop = mapper.findDescriptor(i);
		// build getters methods list
		List readers = new ArrayList();
		while (prop != null) {
			readers.add(prop.getReadMethod());
			i++;
			prop = mapper.findDescriptor(i);

		}
		return readers;
	}

	/**
	 * Processes a list of objects.
	 * 
	 * @param csv - csvWriter
	 * @param objects - list of objects to process
	 * @param getters - list of getter methods to retrieve the data from the objects.
	 * @throws IntrospectionException - thrown if there is an failure in Introspection.
	 * @throws IllegalAccessException - thrown if there is an failure in Introspection.
	 * @throws InvocationTargetException - thrown if there is an failure in Introspection.
	 */
	protected void processAndWriteObjects(CSVWriter csv, List objects, List getters) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		for (Object obj : objects) {
			String[] line = processObject(getters, obj);
			csv.writeNext(line);
		}
	}

	/**
	 * Retrieve all the information out of an object.
	 * 
	 * @param getters - List of methods to retrieve information.
	 * @param bean - object to get the information from.
	 * @return String array containing the information from the object
	 * @throws IntrospectionException - thrown by error in introspection.
	 * @throws IllegalAccessException - thrown by error in introspection.
	 * @throws InvocationTargetException - thrown by error in introspection.
	 */
	@Override
	protected String[] processObject(List getters, Object bean) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		String[] results = new String[getters.size()];
		for (int i = 0; i < getters.size(); i++) {
			Method getter = getters.get(i);
			Object value = getter.invoke(bean, (Object[]) null);
			Class type = (Class) getter.getReturnType();
			if (value == null) {
				results[i] = "null";
			} else {
				results[i] = transformerManager.transform(type, String.class, value);
			}
		}
		return results;
	}

}