/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.io.converters; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.lang.reflect.Array; /** * This class provides a converter that is able to read and write arrays of * objects. Therefore the array converter needs a converter that is able to read * and write the single objects of the array's component type. First the * converter reads or writes the length of the array. Thereafter the objects * are read or written. * * <p>Example usage (1). * <code><pre> * // create an array of 3 object * * Vector<String>[] array = new Vector[3]; * * // initialize the objects with vectors and fill them with strings * * array[0] = new Vector<String>(); * array[0].add("This"); * array[0].add("is"); * array[0].add("a"); * array[0].add("vector."); * array[1] = new Vector<String>(); * array[1].add("This"); * array[1].add("also."); * array[2] = new Vector<String>(); * array[2].add("No"); * array[2].add("it"); * array[2].add("does"); * array[2].add("not"); * array[2].add("really"); * array[2].add("make"); * array[2].add("any"); * array[2].add("sense."); * * // create a converter for vectors * * Converter<Vector<String>> converter = new Converter<Vector<String>>() { * * // how to write a vector * * public void write(DataOutput dataOutput, Vector<String> object) throws IOException { * * // write the size of the vector at first * * IntegerConverter.DEFAULT_INSTANCE.writeInt(dataOutput, object.size()); * * // thereafter write the elements of the vector * * for (String string : object) * StringConverter.DEFAULT_INSTANCE.write(dataOutput, string); * } * * // how to read a vector * * public Vector<String> read(DataInput dataInput, Vector<String> object) throws IOException { * * // read the size of the vector at first * * int size = IntegerConverter.DEFAULT_INSTANCE.readInt(dataInput); * * // create a new vector * * Vector<String> vector = new Vector<String>(); * * // thereafter read the elements of the vector * * for (int i = 0; i < size; i++) * vector.add(StringConverter.DEFAULT_INSTANCE.read(dataInput)); * * // return the restored vector * * return vector; * } * }; * * // create an array converter that is able to read and write * // arrays of vectors * * ArrayConverter<Vector<String>> arrayConverter = new ArrayConverter<Vector<String>>(converter); * * // create a byte array output stream * * ByteArrayOutputStream output = new ByteArrayOutputStream(); * * // write array to the output stream * * arrayConverter.write(new java.io.DataOutputStream(output), array); * * // create a byte array input stream on the output stream * * ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); * * // reset the array * * array = null; * * // read array from the input stream * * array = arrayConverter.read(new DataInputStream(input), new Vector[0]); * * // print the array (the data of the vectors) * * for (Vector<String> vector : array) * System.out.println(vector); * * // close the streams after use * * input.close(); * output.close(); * </pre></code></p> * * @param <T> the component type of the array to be converted. * @see DataInput * @see DataOutput * @see IOException */ public class ArrayConverter<T> extends Converter<T[]> { /** * The field <code>converter</code> refers to a converter that is able to * read and write the single objects. */ protected Converter<T> converter; /** * Constructs a new object array converter that is able to read and write * object arrays. The specified converter is used for reading and writing * the single objects. * * @param converter a converter that is able to read and write the single * objects. */ public ArrayConverter(Converter<T> converter) { this.converter = converter; } /** * Reads an array of objects from the specified data input and returns the * restored array. In case that the specified object is not * <code>null</code>, this implementation calls the converter with each * object of this array on reading. When the given array is not suitable * for the objects stored in the stream, a new array is created via * reflection. * * @param dataInput the stream to read the object array from. * @param object the object array to be restored. When it is * <code>null</code> a new array is created via reflection. * @return the restored array of bjects. * @throws IOException if I/O errors occur. */ @Override @SuppressWarnings("unchecked") // an array of the correct type is created by using reflection public T[] read(DataInput dataInput, T[] object) throws IOException { int size = dataInput.readInt(); if (object == null) throw new IllegalArgumentException("an array of the generic type must be specified"); if (size > object.length) object = (T[])Array.newInstance(object.getClass().getComponentType(), size); for (int i = 0; i < size; i++) object[i] = converter.read(dataInput, object[i]); return object; } /** * Writes the specified array of objects to the specified data output. * * <p>This implementation first writes the length of the array to the data * output. Thereafter the objects are written by calling the write method * of the internally used converter.</p> * * @param dataOutput the stream to write the object array to. * @param object the object array that should be written to the data * output. * @throws IOException includes any I/O exceptions that may occur. */ @Override public void write(DataOutput dataOutput, T[] object) throws IOException { dataOutput.writeInt(object.length); for (T o : object) converter.write(dataOutput, o); } }