package org.webpieces.router.impl.params; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.function.Function; import javax.inject.Singleton; import org.webpieces.router.api.ObjectStringConverter; /** * This is THE class to translate objects to strings and strings to objects. Overriding this, you can also add types * to translate as well like jodatime dates or java.util.Dates etc. This translator applies to EVERYTHING in the * platform OR if it doesn't, that is a bug(I don't think we missed any locations). This includes rendering in * templates, path parames, etc. etc. * * @author dhiller * */ @Singleton public class ObjectTranslator { protected Map<Class<?>, ObjectStringConverter<?>> classToConverter = new HashMap<>(); protected Map<Class<?>, ObjectStringConverter<?>> appConverters; protected ObjectStringConverter<Object> SIMPLE_CONVERTER = new SimpleConverter(); public ObjectTranslator() { add(Boolean.class, s -> s == null ? null : Boolean.parseBoolean(s), s -> s == null ? null : s.toString()); add(Byte.class, s -> s == null ? null : Byte.parseByte(s), s -> s == null ? null : s.toString()); add(Short.class, s -> s == null ? null : Short.parseShort(s), s -> s == null ? null : s.toString()); add(Integer.class, s -> s == null ? null : Integer.parseInt(s), s -> s == null ? null : s.toString()); add(Long.class, s -> s == null ? null : Long.parseLong(s), s -> s == null ? null : s.toString()); add(Float.class, s -> s == null ? null : Float.parseFloat(s), s -> s == null ? null : s.toString()); add(Double.class, s -> s == null ? null : Double.parseDouble(s), s -> s == null ? null : s.toString()); add(String.class, s -> s, s -> s); add(Boolean.TYPE, s -> Boolean.parseBoolean(s), s -> s.toString()); add(Byte.TYPE, s -> Byte.parseByte(s), s -> s.toString()); add(Short.TYPE, s -> Short.parseShort(s), s -> s.toString()); add(Integer.TYPE, s -> Integer.parseInt(s), s -> s.toString()); add(Long.TYPE, s -> Long.parseLong(s), s -> s.toString()); add(Float.TYPE, s -> Float.parseFloat(s), s -> s.toString()); add(Double.TYPE, s -> Double.parseDouble(s), s -> s.toString()); } private <T> void add(Class<T> clazz, Function<String, T> toObj, Function<T, String> toStr) { classToConverter.put(clazz, new PrimitiveConverter<T>(clazz, toObj, toStr)); } @SuppressWarnings("unchecked") public <T> ObjectStringConverter<T> getConverterFor(T bean) { if(bean == null) { return (ObjectStringConverter<T>) SIMPLE_CONVERTER; } ObjectStringConverter<T> converter = (ObjectStringConverter<T>) getConverter(bean.getClass()); if(converter != null) return converter; return (ObjectStringConverter<T>) SIMPLE_CONVERTER; } @SuppressWarnings({ "rawtypes", "unchecked" }) public <T> ObjectStringConverter<T> getConverter(Class<T> fieldClass) { ObjectStringConverter webConverter = classToConverter.get(fieldClass); if(webConverter != null) return webConverter; return (ObjectStringConverter<T>) appConverters.get(fieldClass); } @SuppressWarnings("rawtypes") public void install(Set<ObjectStringConverter> converters) { //have to recreate for dev mode. prod only calls this once appConverters = new HashMap<>(); for(ObjectStringConverter converter : converters) { appConverters.put(converter.getConverterType(), converter); } } }