/* 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.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
/**
* This class represents a converter for objects of type {@link java.util.Map}.
*
* @param <K> the type of keys used by the maps to be converted.
* @param <V> the type of values used by the maps to be converted.
*/
public class MapConverter<K, V> extends Converter<Map<K, V>> {
/**
* A factory method which returns a new hash-map.
*/
public static Function<Object, HashMap<Object, Object>> HASH_MAP_FACTORY_METHOD = new AbstractFunction<Object, HashMap<Object, Object>>() {
@Override
public HashMap<Object, Object> invoke() {
return new HashMap<Object, Object>();
}
};
/**
* A factory method which returns a new tree-map.
*/
public static Function<Object, TreeMap<Object, Object>> TREE_MAP_FACTORY_METHOD = new AbstractFunction<Object, TreeMap<Object, Object>>() {
@Override
public TreeMap<Object, Object> invoke() {
return new TreeMap<Object, Object>();
}
};
/**
* A multi converter used internally.
*/
protected MultiConverter<Map.Entry<?, ?>> mapEntryConverter;
/**
* A factory method which produces a new map. This function can be one of
* the above defined functions.
*/
protected Function<Object, ? extends Map<K, V>> mapCreator;
/**
* Constructs a new converter for map structures.
*
* @param keyConverter the converter for the keys of the map entries.
* @param valueConverter the converter for the values of the map entries.
* @param mapCreator a factory method which produces a new map. This
* function can be one of the above defined functions.
*/
public MapConverter(Converter<K> keyConverter, Converter<V> valueConverter, Function<Object, ? extends Map<K, V>> mapCreator) {
this.mapCreator = mapCreator;
this.mapEntryConverter = new MultiConverter<Map.Entry<?, ?>>(
xxl.core.collections.MapEntry.FACTORY_METHOD,
xxl.core.collections.MapEntry.TO_OBJECT_ARRAY_FUNCTION,
keyConverter,
valueConverter
);
}
/**
* Reads the state (the attributes) for the specified object from the
* specified data input and returns the restored object.
*
* @param dataInput the stream to read data from in order to restore the
* object.
* @param object the map to be restored. If the object is null it is
* initialized by invoking the factory method.
* @return the restored object.
* @throws IOException if I/O errors occur.
*/
@Override
@SuppressWarnings("unchecked") // due to the given functions, the used multi-converter can only generate the required map entries
public Map<K, V> read(DataInput dataInput, Map<K, V> object) throws IOException {
if (object == null)
object = mapCreator.invoke();
int size = dataInput.readInt();
while (size-- > 0) {
Map.Entry<K, V> me = (Map.Entry<K, V>)mapEntryConverter.read(dataInput);
object.put(me.getKey(), me.getValue());
}
return object;
}
/**
* Writes the state (the attributes) of the specified object to the
* specified data output.
*
* @param dataOutput the stream to write the state (the attributes) of the
* object to.
* @param object The map whose state should be written to the data output.
* @throws IOException includes any I/O exceptions that may occur.
*/
@Override
public void write(DataOutput dataOutput, Map<K, V> object) throws IOException {
dataOutput.writeInt(object.size());
for (Map.Entry<K, V> me : object.entrySet())
mapEntryConverter.write(dataOutput, me);
}
}