/**
*
*/
package org.openflexo.model;
import java.util.Hashtable;
import java.util.Map;
import org.openflexo.model.StringConverterLibrary.Converter;
import org.openflexo.model.exceptions.InvalidDataException;
import org.openflexo.model.factory.ModelFactory;
import org.openflexo.model.factory.ProxyMethodHandler;
import com.google.common.primitives.Primitives;
public class StringEncoder {
private Map<Class<?>, Converter<?>> converters = new Hashtable<Class<?>, Converter<?>>();
private ModelFactory modelFactory;
public StringEncoder(ModelFactory modelFactory) {
this.modelFactory = modelFactory;
}
public String toString(Object object) throws InvalidDataException {
if (object == null) {
return null;
}
Class<? extends Object> aClass = object.getClass();
ProxyMethodHandler<?> handler = null;
if (modelFactory != null) {
handler = modelFactory.getHandler(object);
}
if (handler != null) {
aClass = handler.getModelEntity().getImplementedInterface();
}
Converter converter = converterForClass(aClass);
if (converter != null) {
return converter.convertToString(object);
} else {
if (object instanceof Enum) {
return ((Enum) object).name();
}
throw new InvalidDataException("Supplied value has no converter for type " + aClass.getName());
}
}
public <T> T fromString(Class<T> type, String value) throws InvalidDataException {
if (value == null) {
return null;
}
Converter<T> converter = converterForClass(type);
if (converter != null) {
return converter.convertFromString(value, modelFactory);
} else if (type.isEnum()) {
try {
return (T) Enum.valueOf((Class) type, value);
} catch (IllegalArgumentException e) {
System.err.println("Could not decode " + value + " as a " + type);
return null;
}
} else {
throw new InvalidDataException("Supplied value has no converter for type " + type.getName());
}
}
/**
* Hereunder are all the non-static elements of this class. Only those should be used.
*/
public <T> Converter<T> addConverter(Converter<T> converter) {
converters.put(converter.getConverterClass(), converter);
if (Primitives.isWrapperType(converter.getConverterClass())) {
converters.put(Primitives.unwrap(converter.getConverterClass()), converter);
}
return converter;
}
/**
* @param converter
*/
public void removeConverter(Converter<?> converter) {
converters.remove(converter.getConverterClass());
}
public <T> Converter<T> converterForClass(Class<T> objectType) {
// 1. We try with custom converters
Converter<T> converterForClass = converterForClass(objectType, converters);
if (converterForClass == null) {
// 2. We try with model-defined converters
converterForClass = converterForClass(objectType, StringConverterLibrary.getInstance().getConverters());
}
return converterForClass;
}
public static <T> Converter<T> converterForClass(Class<T> objectType, Map<Class<?>, Converter<?>> convertersMap) {
Converter<?> returned;
Class<?> candidate = objectType;
do {
returned = convertersMap.get(candidate);
if (candidate.equals(Object.class)) {
candidate = null;
} else {
candidate = candidate.getSuperclass();
}
} while (returned == null && candidate != null);
return (Converter<T>) returned;
}
public boolean isConvertable(Class<?> type) {
return converterForClass(type) != null || type.isEnum();
}
}