/* * Copyright 2014 Artur. * * 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.jaxygen.typeconverter; import java.util.HashMap; import java.util.Map; import org.jaxygen.typeconverter.exceptions.ConversionError; /** * Class is a registry of the TypeConverter classes. Once the converter * registered it will be used whenever once calls * {@link TypeConverterFactory#convert(java.lang.Object, java.lang.Class)} * method. Factory automatically selects the required converter object by * convert method parameter classes. * * * @author Artur */ public class TypeConverterFactory { public final static String DEFAULT_FACTORY = ".default_TypeConverterFactory"; private final Map<Class, Map<Class, TypeConverter>> converters = new HashMap<Class, Map<Class, TypeConverter>>(); private final static Map<String, TypeConverterFactory> factories = new HashMap<String, TypeConverterFactory>(); static { factories.put(DEFAULT_FACTORY, new TypeConverterFactory()); } /** * Get default instance of the TypeConverterFactory class. * * @return A default instance of TypeConverterFactory. */ public static TypeConverterFactory instance() { return factories.get(DEFAULT_FACTORY); } /** * Get named instance of the TypeConverterFactory class. * * @param name specific name of the factory. * @return A named instance of type converters factory. */ public static synchronized TypeConverterFactory instance(final String name) { TypeConverterFactory rc = factories.get(name); if (rc == null) { rc = new TypeConverterFactory(); factories.put(name, rc); } return rc; } /** * Add a new converter to this converters factory. * * @param converter Add a new type converter to the registry. */ public void registerConverter(final TypeConverter converter) { final Class from = converter.from(); final Class to = converter.to(); registerConverter(from, to, converter); } /** * Add a new converter to this converters factory. * * @param <FROM> Type from which the conversion is done. * @param <TO> Type to which the conversion is done. * @param fromClass The class from which the conversion will be done. * @param toClass The class into which conversion will be done. * @param converter Converter used to replace from fromClass to toClass */ public <FROM, TO> void registerConverter(final Class<FROM> fromClass, final Class<TO> toClass, TypeConverter<? extends FROM, ? extends TO> converter) { Map<Class, TypeConverter> toMap; if (converters.containsKey(fromClass) == false) { toMap = new HashMap<Class, TypeConverter>(); converters.put(fromClass, toMap); } else { toMap = converters.get(fromClass); } toMap.put(toClass, converter); } /** * Get the converter which could translate an object from class from to * class to. * * @param <FROM> Type from which the conversion is done. * @param <TO> Type to which the conversion is done. * @param from The class from which the conversion will be done. * @param to The class into which conversion will be done. * @return Type converter that changes from FROM to TO. */ public <FROM, TO> TypeConverter<FROM, TO> get(final Class<FROM> from, final Class<TO> to) { TypeConverter<FROM, TO> converter = null; if (converters.containsKey(from) && converters.get(from).containsKey(to)) { converter = converters.get(from).get(to); } if (converter == null) { for (Map<Class, TypeConverter> tcm : converters.values()) { for (TypeConverter tc : tcm.values()) { Class tcFrom = tc.from(); Class tcTo = tc.to(); if (tcFrom.isAssignableFrom(from) && tcTo.isAssignableFrom(to)) { converter = tc; break; } } } } return converter; } ; /** Find converter that converts given object from class FROM to class TO. * Note that the from parameter could not be null. If you expect that from * parameter could be null, please use {@link TypeConverterFactory#convert(java.lang.Object, java.lang.Class, java.lang.Class)} method, * * @param <FROM> Type from which the conversion is done. * @param <TO> Type to which the conversion is done. * @param from The object from which the conversion will be done. Note, it could not be null. * @param toClass The class into which conversion will be done. * @return Type converter that changes from FROM to TO. * @throws ConversionError Conversion error. */ public <FROM, TO> TO convert(final FROM from, final Class<TO> toClass) throws ConversionError { @SuppressWarnings("unchecked") TypeConverter<FROM, TO> converter = get((Class<FROM>) from.getClass(), toClass); if (converter == null) { throw new ConversionError("Could not find converter from class " + from.getClass() + " to class " + toClass); } return (TO) converter.convert(from); } /** * Convenient method used in case if the from object could be null * * @param <FROM> Type from which the conversion is done. * @param <TO> Type to which the conversion is done. * @param from Object that well be converted. * @param fromClass The class from which the conversion will be done. * @param toClass The class into which conversion will be done. * @return Instance of toClass. * @throws ConversionError Conversion failed. */ public <FROM, TO> TO convert(final FROM from, final Class<FROM> fromClass, final Class<TO> toClass) throws ConversionError { @SuppressWarnings("unchecked") TypeConverter<FROM, TO> converter = get(fromClass, toClass); if (converter == null) { throw new ConversionError("Could not find converter from class " + fromClass + " to class " + toClass); } return (TO) converter.convert(from); } }