package org.simpleflatmapper.converter; import org.simpleflatmapper.converter.impl.JavaBaseConverterFactoryProducer; import org.simpleflatmapper.converter.impl.IdentityConverter; //IFJAVA8_START import org.simpleflatmapper.converter.impl.time.JavaTimeConverterFactoryProducer; //IFJAVA8_END import org.simpleflatmapper.util.Consumer; import org.simpleflatmapper.util.ProducerServiceLoader; import org.simpleflatmapper.util.TypeHelper; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ConverterService { private static final ConverterService INSTANCE = new ConverterService(getConverterFactories()); private static List<ConverterFactory> getConverterFactories() { final List<ConverterFactory> converterFactories = new ArrayList<ConverterFactory>(); Consumer<ConverterFactory<?, ?>> factoryConsumer = new Consumer<ConverterFactory<?, ?>>() { @Override public void accept(ConverterFactory<?, ?> converterFactory) { converterFactories.add(converterFactory); } }; new JavaBaseConverterFactoryProducer().produce(factoryConsumer); //IFJAVA8_START new JavaTimeConverterFactoryProducer().produce(factoryConsumer); //IFJAVA8_END ProducerServiceLoader.produceFromServiceLoader(ConverterFactoryProducer.class, factoryConsumer); return converterFactories; } public static ConverterService getInstance() { return INSTANCE; } private ConverterService(List<ConverterFactory> converters) { this.converters = converters; } public <F, P> Converter<? super F, ? extends P> findConverter(Class<F> inType, Class<P> outType, Object... params) { return findConverter((Type)inType, (Type)outType, params); } @SuppressWarnings("unchecked") public <F, P> Converter<? super F, ? extends P> findConverter(Type inType, Type outType, Object... params) { List<ScoredConverterFactory> potentials = new ArrayList<ScoredConverterFactory>(); List<ScoredConverterFactory> tails = new ArrayList<ScoredConverterFactory>(); if (TypeHelper.isAssignable(outType, inType)) { return new IdentityConverter(); } ConvertingTypes targetedTypes = new ConvertingTypes(inType, outType); for(ConverterFactory converterFactory : converters) { ConvertingScore score = converterFactory.score(targetedTypes); int globalScore = score.getScore(); if (globalScore >= 0) { potentials.add(new ScoredConverterFactory(globalScore, converterFactory)); } else { int tailScore = score.getToScore(); if (tailScore >= 0) { tails.add(new ScoredConverterFactory(tailScore, converterFactory)); } } } if (potentials.size() > 0) { Collections.sort(potentials); return (Converter<F, P>) potentials.get(0).converterFactory.newConverter(targetedTypes, params); } else { if (tails.size() > 0) { Collections.sort(tails); for(ScoredConverterFactory sfactory : tails) { Type tailFactoryInType = sfactory.converterFactory.getFromType(); Converter converter = (Converter<? super F, ? extends P>) findConverter(inType, tailFactoryInType, params); if (converter != null) { return new ComposedConverter(converter, sfactory.converterFactory.newConverter(new ConvertingTypes(tailFactoryInType, targetedTypes.getTo()), params)); } } } return null; } } private final List<ConverterFactory> converters; private static class ScoredConverterFactory implements Comparable<ScoredConverterFactory>{ private final int score; private final ConverterFactory converterFactory; private ScoredConverterFactory(int score, ConverterFactory converterFactory) { this.score = score; this.converterFactory = converterFactory; } @Override public int compareTo(ScoredConverterFactory o) { return o.score - score; } } }