Skip to main content
Removed the code tics from output
Source Link
coderodde
  • 29.8k
  • 14
  • 77
  • 194
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
```
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
```
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
Code snippets rearranged (without altering the code) to make it easier to follow the code. Tag "generics" added.
Source Link

I was hoping to make it cleaner and more robust.

Converter:

package solution.common.converter;

import java.util.Optional;

public interface ConverterServiceConverter<T> {
    <T><S> Optional<T> convert(ObjectS value, Class<T> targetType);
}

Converter implementation:

package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

public interfaceclass BasicConverter<T> implements Converter<T> {
    private final Map<Class<?>, Function<?, Optional<T>>> mappings = new HashMap<>();

    public <S> void addMapping(Class<S> sourceType, Function<S, Optional<T>> mappingFunction) {
        mappings.put(sourceType, mappingFunction);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <S> Optional<T> convert(S value) {
        Class<?> valueType = value.getClass();
        Function<? super S, Optional<T>> mapping = (Function<? super S, Optional<T>>) getMappingForType(valueType);
        Optional<T> optionalValue = mapping.apply(value);
        return optionalValue;
    }

    private Function<?, Optional<T>> getMappingForType(Class<?> type) {
        Function<?, Optional<T>> mapping = mappings.containsKey(type) ?
                mappings.get(type) :
                findSuperTypeMapping(type);
        return mapping;
    }

    @SuppressWarnings("unchecked")
    private <S> Function<? super S, Optional<T>> findSuperTypeMapping(Class<S> valueType) {
        for (Class<?> aClass : mappings.keySet()) {
            if (aClass.isAssignableFrom(valueType))
                return (Function<? super S, Optional<T>>) mappings.get(aClass);
        }
        return noopMapping();
    }

    private <S> Function<S, Optional<T>> noopMapping() {
        return input -> Optional.empty();
    }
}

ConverterService:

package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class BasicConverterService implementsinterface ConverterService {
    private final Map<Class<?>, Converter<?>> converterMap = new HashMap<>();

    public <T> void addConverter(Class<T> targetType, Converter<T> converter) {
        converterMap.put(targetType, converter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> Optional<T> convert(Object value, Class<T> targetType) {
        if (targetType.isAssignableFrom(value.getClass()))
            return (Optional<T>) Optional.of(value);
        Converter<?> converter = (converterMap.containsKey(targetType)) ?
                converterMap.get(targetType) :
                findSubtypeConverter(targetType);
        return (Optional<T>) converter.convert(value);
    }

    private Converter<?> findSubtypeConverter(Class<?> targetType) {
        for (Class<?> aClass : converterMap.keySet()) {
            if (targetType.isAssignableFrom(aClass))
                return converterMap.get(aClass);
        }
        return noopConverter();
    }

    private <T> Converter<T> noopConverter() {
        return new Converter<T>() {
            @Override
            public <S> Optional<T> convert(S value) {
                return Optional.empty();
            }
        };
    }
}

ConverterService implementation:

package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

public class BasicConverter<T>BasicConverterService implements Converter<T>ConverterService {
    private final Map<Class<?>, Function<Converter<?, Optional<T>>>>> mappingsconverterMap = new HashMap<>();

    public <S><T> void addMappingaddConverter(Class<S> sourceType,Class<T> Function<StargetType, Optional<T>>Converter<T> mappingFunctionconverter) {
        mappingsconverterMap.put(sourceTypetargetType, mappingFunctionconverter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <S><T> Optional<T> convert(SObject value, Class<T> targetType) {
        Class<?> valueType =if (targetType.isAssignableFrom(value.getClass();))
        Function<? super S, Optional<T>> mappingreturn =(Optional<T>) Optional.of(Function<value);
        Converter<?> superconverter S,= Optional<T>>(converterMap.containsKey(targetType)) getMappingForType?
                converterMap.get(valueTypetargetType); :
        Optional<T> optionalValue = mapping.apply     findSubtypeConverter(valuetargetType);
        return optionalValue;(Optional<T>) converter.convert(value);
    }

    private Function<Converter<?, Optional<T>>> getMappingForTypefindSubtypeConverter(Class<?> typetargetType) {
        Function<?,for Optional<T>>(Class<?> mappingaClass =: mappingsconverterMap.containsKeykeySet(type)) ?{
               if mappings(targetType.getisAssignableFrom(typeaClass) :)
                findSuperTypeMappingreturn converterMap.get(typeaClass);
        return mapping;}
    }

    @SuppressWarningsreturn noopConverter("unchecked");
    private}

 <S> Function<? super S,private Optional<T>><T> findSuperTypeMapping(Class<S>Converter<T> valueTypenoopConverter() {
        for (Class<?> aClassreturn :new mappings.keySetConverter<T>()) {
            if (aClass.isAssignableFrom(valueType))@Override
              public <S> returnOptional<T> convert(Function<? super S, Optional<T>>value) mappings.get(aClass);{
        }
        return noopMappingOptional.empty();
    }

    private <S> Function<S, Optional<T>> noopMapping() {}
        return input -> Optional.empty()};
    }
}

Tests:

package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
```

I was hoping to make it cleaner and more robust

package solution.common.converter;

import java.util.Optional;

public interface ConverterService {
    <T> Optional<T> convert(Object value, Class<T> targetType);
}
package solution.common.converter;

import java.util.Optional;

public interface Converter<T> {
    <S> Optional<T> convert(S value);
}
package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class BasicConverterService implements ConverterService {
    private final Map<Class<?>, Converter<?>> converterMap = new HashMap<>();

    public <T> void addConverter(Class<T> targetType, Converter<T> converter) {
        converterMap.put(targetType, converter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> Optional<T> convert(Object value, Class<T> targetType) {
        if (targetType.isAssignableFrom(value.getClass()))
            return (Optional<T>) Optional.of(value);
        Converter<?> converter = (converterMap.containsKey(targetType)) ?
                converterMap.get(targetType) :
                findSubtypeConverter(targetType);
        return (Optional<T>) converter.convert(value);
    }

    private Converter<?> findSubtypeConverter(Class<?> targetType) {
        for (Class<?> aClass : converterMap.keySet()) {
            if (targetType.isAssignableFrom(aClass))
                return converterMap.get(aClass);
        }
        return noopConverter();
    }

    private <T> Converter<T> noopConverter() {
        return new Converter<T>() {
            @Override
            public <S> Optional<T> convert(S value) {
                return Optional.empty();
            }
        };
    }
}
package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

public class BasicConverter<T> implements Converter<T> {
    private final Map<Class<?>, Function<?, Optional<T>>> mappings = new HashMap<>();

    public <S> void addMapping(Class<S> sourceType, Function<S, Optional<T>> mappingFunction) {
        mappings.put(sourceType, mappingFunction);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <S> Optional<T> convert(S value) {
        Class<?> valueType = value.getClass();
        Function<? super S, Optional<T>> mapping = (Function<? super S, Optional<T>>) getMappingForType(valueType);
        Optional<T> optionalValue = mapping.apply(value);
        return optionalValue;
    }

    private Function<?, Optional<T>> getMappingForType(Class<?> type) {
        Function<?, Optional<T>> mapping = mappings.containsKey(type) ?
                mappings.get(type) :
                findSuperTypeMapping(type);
        return mapping;
    }

    @SuppressWarnings("unchecked")
    private <S> Function<? super S, Optional<T>> findSuperTypeMapping(Class<S> valueType) {
        for (Class<?> aClass : mappings.keySet()) {
            if (aClass.isAssignableFrom(valueType))
                return (Function<? super S, Optional<T>>) mappings.get(aClass);
        }
        return noopMapping();
    }

    private <S> Function<S, Optional<T>> noopMapping() {
        return input -> Optional.empty();
    }
}
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}

I was hoping to make it cleaner and more robust.

Converter:

package solution.common.converter;

import java.util.Optional;

public interface Converter<T> {
    <S> Optional<T> convert(S value);
}

Converter implementation:

package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

public class BasicConverter<T> implements Converter<T> {
    private final Map<Class<?>, Function<?, Optional<T>>> mappings = new HashMap<>();

    public <S> void addMapping(Class<S> sourceType, Function<S, Optional<T>> mappingFunction) {
        mappings.put(sourceType, mappingFunction);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <S> Optional<T> convert(S value) {
        Class<?> valueType = value.getClass();
        Function<? super S, Optional<T>> mapping = (Function<? super S, Optional<T>>) getMappingForType(valueType);
        Optional<T> optionalValue = mapping.apply(value);
        return optionalValue;
    }

    private Function<?, Optional<T>> getMappingForType(Class<?> type) {
        Function<?, Optional<T>> mapping = mappings.containsKey(type) ?
                mappings.get(type) :
                findSuperTypeMapping(type);
        return mapping;
    }

    @SuppressWarnings("unchecked")
    private <S> Function<? super S, Optional<T>> findSuperTypeMapping(Class<S> valueType) {
        for (Class<?> aClass : mappings.keySet()) {
            if (aClass.isAssignableFrom(valueType))
                return (Function<? super S, Optional<T>>) mappings.get(aClass);
        }
        return noopMapping();
    }

    private <S> Function<S, Optional<T>> noopMapping() {
        return input -> Optional.empty();
    }
}

ConverterService:

package solution.common.converter;

import java.util.Optional;

public interface ConverterService {
    <T> Optional<T> convert(Object value, Class<T> targetType);
}

ConverterService implementation:

package solution.common.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class BasicConverterService implements ConverterService {
    private final Map<Class<?>, Converter<?>> converterMap = new HashMap<>();

    public <T> void addConverter(Class<T> targetType, Converter<T> converter) {
        converterMap.put(targetType, converter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> Optional<T> convert(Object value, Class<T> targetType) {
        if (targetType.isAssignableFrom(value.getClass()))
            return (Optional<T>) Optional.of(value);
        Converter<?> converter = (converterMap.containsKey(targetType)) ?
                converterMap.get(targetType) :
                findSubtypeConverter(targetType);
        return (Optional<T>) converter.convert(value);
    }

    private Converter<?> findSubtypeConverter(Class<?> targetType) {
        for (Class<?> aClass : converterMap.keySet()) {
            if (targetType.isAssignableFrom(aClass))
                return converterMap.get(aClass);
        }
        return noopConverter();
    }

    private <T> Converter<T> noopConverter() {
        return new Converter<T>() {
            @Override
            public <S> Optional<T> convert(S value) {
                return Optional.empty();
            }
        };
    }
}

Tests:

package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
```
added 2 characters in body
Source Link
toolic
  • 6.2k
  • 4
  • 20
  • 75
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
```
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
```
package solution.common.di;

import solution.common.converter.BasicConverter;
import solution.common.converter.BasicConverterService;
import solution.common.converter.Converter;
import solution.common.converter.ConverterService;
import solution.common.date.DateUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Optional;

public class Converters {
    public static ConverterService converterService() {
        BasicConverterService converterService = new BasicConverterService();
        converterService.addConverter(Date.class, toDateConverter());
        converterService.addConverter(Byte.class, toByteConverter());
        converterService.addConverter(Short.class, toShortConverter());
        converterService.addConverter(Integer.class, toIntegerConverter());
        converterService.addConverter(BigInteger.class, toBigIntegerConverter());
        converterService.addConverter(Long.class, toLongConverter());
        converterService.addConverter(Float.class, toFloatConverter());
        converterService.addConverter(Double.class, toDoubleConverter());
        converterService.addConverter(BigDecimal.class, toBigDecimalConverter());
        converterService.addConverter(String.class, toStringConverter());
        return converterService;
    }

    private static Converter<Date> toDateConverter() {
        BasicConverter<Date> converter = new BasicConverter<>();
        converter.addMapping(Object.class, DateUtils::asDate);
        return converter;
    }

    private static Converter<Byte> toByteConverter() {
        BasicConverter<Byte> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Byte::parseByte));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::byteValue));
        return converter;
    }

    private static Converter<Short> toShortConverter() {
        BasicConverter<Short> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Short::parseShort));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::shortValue));
        return converter;
    }

    private static Converter<Integer> toIntegerConverter() {
        BasicConverter<Integer> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Integer::parseInt));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::intValue));
        return converter;
    }

    private static Converter<Long> toLongConverter() {
        BasicConverter<Long> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Long::parseLong));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::longValue));
        return converter;
    }

    private static Converter<BigInteger> toBigIntegerConverter() {
        BasicConverter<BigInteger> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigInteger::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::longValue)
                .map(BigInteger::valueOf));
        return converter;
    }

    private static Converter<Float> toFloatConverter() {
        BasicConverter<Float> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Float::parseFloat));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::floatValue));
        return converter;
    }

    private static Converter<Double> toDoubleConverter() {
        BasicConverter<Double> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(Double::parseDouble));
        converter.addMapping(Number.class, input -> Optional.of(input).map(Number::doubleValue));
        return converter;
    }

    private static Converter<BigDecimal> toBigDecimalConverter() {
        BasicConverter<BigDecimal> converter = new BasicConverter<>();
        converter.addMapping(String.class, input -> Optional.of(input)
                .map(BigDecimal::new));
        converter.addMapping(Number.class, input -> Optional.of(input)
                .map(Number::doubleValue)
                .map(BigDecimal::new));
        return converter;
    }

    private static Converter<String> toStringConverter() {
        BasicConverter<String> converter = new BasicConverter<>();
        converter.addMapping(Object.class, input -> Optional.of(input).map(Object::toString));
        return converter;
    }
}
added 5 characters in body
Source Link
Sergey
  • 615
  • 1
  • 8
Loading
added 5 characters in body
Source Link
Sergey
  • 615
  • 1
  • 8
Loading
Source Link
Sergey
  • 615
  • 1
  • 8
Loading