/******************************************************************************* * Copyright (c) 2008 Hallvard Traetteberg. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Hallvard Traetteberg - initial API and implementation ******************************************************************************/ package org.eclipse.e4.tm.stringconverter; import java.net.URL; import java.util.HashMap; import org.eclipse.e4.tm.stringconverters.ArrayStringConverter; import org.eclipse.e4.tm.stringconverters.ClassStringConverter; import org.eclipse.e4.tm.stringconverters.FontStringConverter; import org.eclipse.e4.tm.stringconverters.ImageStringConverter; import org.eclipse.e4.tm.stringconverters.NewInstanceStringConverter; import org.eclipse.e4.tm.stringconverters.PointStringConverter; import org.eclipse.e4.tm.stringconverters.RGBStringConverter; import org.eclipse.e4.tm.stringconverters.RectangleStringConverter; import org.eclipse.e4.tm.stringconverters.SWTColorsStringConverter; import org.eclipse.e4.tm.stringconverters.StaticMethodStringConverter; import org.eclipse.e4.tm.stringconverters.StringStringConverter; import org.eclipse.e4.tm.stringconverters.ValueOfStringConverter; import org.eclipse.e4.tm.stringconverters.WebColorStringConverter; import org.eclipse.emf.common.util.URI; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; public class StringConversion { private StringConverterContext stringConverterContext; public void setStringConverterContext(StringConverterContext stringConverterContext) { this.stringConverterContext = stringConverterContext; } private HashMap<Object, StringConverter> stringConverters = new HashMap<Object, StringConverter>(); public StringConversion(boolean addStandardConverters) { if (addStandardConverters) { registerStringConverter(Integer.TYPE, new StaticMethodStringConverter(Integer.class, "decode")); registerStringConverter(Byte.TYPE, new StaticMethodStringConverter(Byte.class, "decode")); registerStringConverter(String.class, new StringStringConverter()); registerStringConverter(RGB.class, new RGBStringConverter()); registerStringConverter(Point.class, new PointStringConverter()); registerStringConverter(Rectangle.class, new RectangleStringConverter()); registerStringConverter(Font.class, new FontStringConverter()); addStringConverter(Color.class, new WebColorStringConverter()); addStringConverter(Color.class, new SWTColorsStringConverter()); addStringConverter(URL.class, new NewInstanceStringConverter()); addStringConverter(URI.class, new StaticMethodStringConverter(URI.class, "createURI")); addStringConverter(Image.class, new ImageStringConverter()); } } public StringConversion() { this(true); } /** * Register a class that can convert from a String to an object of klass. * @param klass The Class object representing the type that will be returned * @param stringConverter The object that can convert a String to that type */ public <T> void registerStringConverter(Class<T> klass, StringConverter stringConverter) { stringConverters.put(klass, stringConverter); stringConverters.put(klass.getName(), stringConverter); } /** * Register an additional class that can convert from a * String to Java type represented by Class klass. Does not clear an existing one, * but makes them operate together, trying each in order until one returns an object. * @param klass The Class object representing the type that will be returned * @param stringConverter The object that can convert a String to that type */ public <T> void addStringConverter(Class<T> klass, StringConverter stringConverter) { StringConverter oldConverter = (StringConverter)stringConverters.get(klass); if (oldConverter == null) { registerStringConverter(klass, stringConverter); } else { if (! (oldConverter instanceof CompositeStringConverter)) { oldConverter = new CompositeStringConverter(oldConverter); stringConverters.put(klass, oldConverter); } ((CompositeStringConverter)oldConverter).addStringConverter(stringConverter); } } private boolean trySuperclassConverters = true; public void setTrySuperclassConverters(boolean trySuperclassConverters) { this.trySuperclassConverters = trySuperclassConverters; } private Class<?> upperSuperclass = null; public void setUpperSuperclass(Class<?> upperSuperclass) { this.upperSuperclass = upperSuperclass; } /** * Parse a String value into an object of type klass * @param value The value to convert * @param klass The Class into which value should be converted * @return Object the converted value as a klass object */ public <T> T convert(String value, Class<T> klass) { String stringValue = value; while (stringValue != null) { Class<?> superClass = klass; Class<T> objectClass = ClassStringConverter.getObjectClass(klass); Object lastResult = null; do { Object result = null; StringConverter converter = getStringConverter(superClass); if (converter != null) { try { result = converter.convert(stringValue, klass, stringConverterContext); } catch (Exception e) { throw new RuntimeException("Exception when converting " + value + " for " + superClass, e); } } else if (! trySuperclassConverters) { throw new RuntimeException("Unable to find a converter for type: " + klass.getName()); } if (result != null) { if (objectClass.isInstance(result)) { return (T)result; } else { lastResult = result; } } superClass = superClass.getSuperclass(); } while (trySuperclassConverters && superClass != null && superClass != upperSuperclass); throw new RuntimeException(value + " (" + stringValue + ")" + " could not be parsed into " + klass + ", but to " + lastResult); } return null; } private StringConverter getStringConverter(Class<?> klass) { StringConverter converter = (StringConverter)stringConverters.get(klass); if (converter == null) { converter = (StringConverter)stringConverters.get(klass.getName()); } if (converter == null) { if (klass.isArray()) { converter = new ArrayStringConverter(); } else if (ValueOfStringConverter.supportsClass(klass)) { converter = new ValueOfStringConverter(); } if (converter != null) { stringConverters.put(klass, converter); } else { converter = (StringConverter)stringConverters.get(Object.class); } } return converter; } }