I have an interface to convert object to string:
public interface Converter {
String asString(T object);
}
And a map to store
First, you should encapsulate the map inside a helper class like this, whose operations preserve the invariant (that Class<T>
maps to Converter<T>
):
public class ConverterMap {
Map<Class<?>, Converter<?>> converterMap = new HashMap<Class<?>, Converter<?>>();
public <T> void addConverter(Class<T> clazz, Converter<T> converter) {
converterMap.put(clazz, converter);
}
@SuppressWarnings("unchecked")
public <T> Converter<T> getConverter(Class<T> clazz) {
return (Converter<T>)converterMap.get(clazz);
}
}
Now, to break down the task, let's take the small step of writing a function that takes any object and converts it based on the converter map (assuming the object's class is in the converter map):
ConverterMap cm = new ConverterMap;
private static String convert(Object x);
This seems simple, but is harder than it looks, because you will run into a special case of the Java type system in how it types .getClass()
. You will have the problem of convincing the compiler that x
is an instance of the parameter of x.getClass()
. The best way to solve this is:
@SuppressWarnings("unchecked")
private static <T> String convert2(Class<T> clazz, Object x) {
return cm.getConverter(clazz).asString((T)x);
// you can alternately do clazz.cast(x) instead of the unchecked cast (T)x
}
private static String convert(Object x) {
return convert2(x.getClass(), x);
}
And then you can solve the rest of the problem:
for (Object datum : data) {
stringData.add(convert(datum));
}
You are facing issue called wildcard capture.
Java is unable to identify the type that will be received from the List<?>
data.
Try refactoring your code in any of the two ways
Method 1: Change your interface as below
interface Converter {
String asString(Object object);
}
Method 2: Helper method to capture wild card by type inference
Create an helper method as below,
// Helper method created so that the wildcard can be captured
// through type inference.
private <T> void helper(List<T> data) {
Map<Class<?>, Converter<T>> converterMap = null;
List<String> stringData = null;
for (T datum : data) {
stringData.add(converterMap.get(datum.getClass()).asString(datum));
}
}
Call this helper method as below
List<?> data = fetchData();
helper(data);
You should change the code like this:
public interface Converter {
String asString(Object object);
}
I think it will work.