I'm writing a small type-conversion framework, based on this interface:
public interface Converter <From,To> {
public To convert(final From from);
}
So that I can write custom type converters such as
public class BigDecimal2Double implements Converter<BigDecimal, Double> {
@Override
public Double convert(final BigDecimal value) {
return value != null ? value.doubleValue() : null;
}
}
The following class is intended to extend the capability of a converter, to deal with Lists of data..
public abstract class ListConverter<From,To> implements Converter<From,To> {
public List<To> convertList(List<From> fromList){
if (fromList == null) {return null;}
List<To> toList = new ArrayList<>(); // DEFAULT IMPLEMENTATION
for(From from: fromList ){
toList.add(this.convert(from));
}
return toList;
}
public static <From,To> ListConverter<From, To> extend(final Converter<From, To> converter){
return new ListConverter<From, To>() {
@Override
public To convert(From from) {
return converter.convert(from);
}
};
}
}
Thus I can write client code such as:
ListConverter<BigDecimal,Double> lcb2d = ListConverter.extend(new BigDecimal2Double());
List<BigDecimal> bdList = retrieveSomeBigDecList();
List<Double> convertedList = lcb2d.convertList(bdList);
As you can see this can only provide a default ArrayList
implementation for the converted list.
I would like to add the capability to provide a different List
implementation from the client code, e.g:
ListConverter<BigDecimal,Double> lcb2d = ListConverter.extend(new BigDecimal2Double());
List<BigDecimal> bdList = retrieveSomeBigDecList();
lcbd.setToListImplementation(LinkedList.class); // How to define such a method?
List<Double> convertedList = lcb2d.convertList(bdList); // would be a LinkedList
How could I accomplish that?
The following code inside ListConverter
class doesn't compile:
private Class<? extends List<To>> toListImplementation = ArrayList.class;
public void setToListImplementation(Class<? extends List<To>> listImpl){
toListImplementation = listImpl;
}
Also how should I replace this line, using the toListImpl
private field?
//... OLD
List<To> toList = new ArrayList<>(); // DEFAULT IMPLEMENTATION
//... NEW
List<To> toList = toListImplementation.newInstance(); // WOULD WORK???
Edit: Java 8 is very cool, I know there are great features. I still work on java 7 though and I would like to accomplish java 5 compliance.
Provide a way for a user of class ListConverter
to supply a factory method to create the specific kind of List
that is needed. Example:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public abstract class ListConverter<From, To> implements Converter<From, To> {
private final Supplier<List<To>> listFactory;
public ListConverter(Supplier<List<To>> listFactory) {
this.listFactory = listFactory;
}
public List<To> convertList(List<From> fromList) {
if (fromList == null) {
return null;
}
List<To> toList = listFactory.get();
for (From from : fromList) {
toList.add(this.convert(from));
}
return toList;
}
public static <From, To> ListConverter<From, To> extend(Converter<From, To> converter, Supplier<List<To>> listFactory) {
return new ListConverter<From, To>(listFactory) {
@Override
public To convert(From from) {
return converter.convert(from);
}
};
}
public static <From, To> ListConverter<From, To> extend(Converter<From, To> converter) {
return extend(converter, ArrayList::new);
}
}
If you would for example want a LinkedList
then you could do:
ListConverter<BigDecimal,Double> lcb2d =
ListConverter.extend(new BigDecimal2Double(), LinkedList::new);
edit - For Java 5-7, you can create a ListFactory
interface:
import java.util.List;
public interface ListFactory<T> {
List<T> newList();
}
And then use that, and use anonymous inner classes instead of Java 8 method references:
import java.util.ArrayList;
import java.util.List;
public abstract class ListConverter<From, To> implements Converter<From, To> {
private final ListFactory<To> listFactory;
public ListConverter(ListFactory<To> listFactory) {
this.listFactory = listFactory;
}
public List<To> convertList(List<From> fromList) {
if (fromList == null) {
return null;
}
List<To> toList = listFactory.newList();
for (From from : fromList) {
toList.add(this.convert(from));
}
return toList;
}
public static <From, To> ListConverter<From, To> extend(Converter<From, To> converter, ListFactory<To> listFactory) {
return new ListConverter<From, To>(listFactory) {
@Override
public To convert(From from) {
return converter.convert(from);
}
};
}
public static <From, To> ListConverter<From, To> extend(Converter<From, To> converter) {
return extend(converter, new ListFactory<To>() {
@Override
public List<To> newList() {
return new ArrayList<To>();
}
});
}
}