package org.jboss.seam.remoting.wrapper; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; /** * String wrapper class. * * @author Shane Bryzak */ public class StringWrapper extends BaseWrapper implements Wrapper { private interface StringConverter { Object convert(String value); } private static final Map<Class,StringConverter> converters = new HashMap<Class,StringConverter>(); static { converters.put(String.class, new StringConverter() { public Object convert(String value) { return value; } }); converters.put(Object.class, new StringConverter() { public Object convert(String value) { return value; } }); converters.put(StringBuilder.class, new StringConverter() { public Object convert(String value) { return new StringBuilder(value); } }); converters.put(StringBuffer.class, new StringConverter() { public Object convert(String value) { return new StringBuffer(value); } }); converters.put(Integer.class, new StringConverter() { public Object convert(String value) { return Integer.valueOf(value); } }); converters.put(Integer.TYPE, new StringConverter() { public Object convert(String value) { return Integer.parseInt(value); } }); converters.put(Long.class, new StringConverter() { public Object convert(String value) { return Long.valueOf(value); } }); converters.put(Long.TYPE, new StringConverter() { public Object convert(String value) { return Long.parseLong(value); } }); converters.put(Short.class, new StringConverter() { public Object convert(String value) { return Short.valueOf(value); } }); converters.put(Short.TYPE, new StringConverter() { public Object convert(String value) { return Short.parseShort(value); } }); converters.put(Boolean.class, new StringConverter() { public Object convert(String value) { return Boolean.valueOf(value); } }); converters.put(Boolean.TYPE, new StringConverter() { public Object convert(String value) { return Boolean.parseBoolean(value); } }); converters.put(Double.class, new StringConverter() { public Object convert(String value) { return Double.valueOf(value); } }); converters.put(Double.TYPE, new StringConverter() { public Object convert(String value) { return Double.parseDouble(value); } }); converters.put(Float.class, new StringConverter() { public Object convert(String value) { return Float.valueOf(value); } }); converters.put(Float.TYPE, new StringConverter() { public Object convert(String value) { return Float.parseFloat(value); } }); converters.put(Character.class, new StringConverter() { public Object convert(String value) { return Character.valueOf(value.charAt(0)); } }); converters.put(Character.TYPE, new StringConverter() { public Object convert(String value) { return value.charAt(0); } }); converters.put(Byte.class, new StringConverter() { public Object convert(String value) { return Byte.valueOf(value); } }); converters.put(Byte.TYPE, new StringConverter() { public Object convert(String value) { return Byte.parseByte(value); } }); converters.put(BigInteger.class, new StringConverter() { public Object convert(String value) { return new BigInteger(value); } }); converters.put(BigDecimal.class, new StringConverter() { public Object convert(String value) { return new BigDecimal(value); } }); } public static final String DEFAULT_ENCODING = "UTF-8"; private static final byte[] STRING_TAG_OPEN = "<str>".getBytes(); private static final byte[] STRING_TAG_CLOSE = "</str>".getBytes(); private static final Class[] COMPATIBLE_CLASSES = { Integer.class, Integer.TYPE, Long.class, Long.TYPE, Short.class, Short.TYPE, Boolean.class, Boolean.TYPE, Double.class, Double.TYPE, Float.class, Float.TYPE, Character.class, Character.TYPE, Byte.class, Byte.TYPE, BigInteger.class, BigDecimal.class, Object.class}; public Object convert(Type type) throws ConversionException { String elementValue = null; try { elementValue = URLDecoder.decode(element.getStringValue(), DEFAULT_ENCODING); } catch (UnsupportedEncodingException ex) { throw new ConversionException("Error converting value - encoding not supported."); } try { if (converters.containsKey(type)) value = converters.get(type).convert(elementValue); else if (type instanceof Class && ( (Class) type).isEnum()) value = Enum.valueOf( (Class) type, elementValue); else // Should never reach this line - calcConverstionScore should guarantee this. throw new ConversionException(String.format( "Value [%s] cannot be converted to type [%s].", elementValue, type)); return value; } catch (Exception ex) { if (ex instanceof ConversionException) throw (ConversionException) ex; else throw new ConversionException(String.format("Could not convert value [%s] to type [%s].", elementValue, type.toString()), ex); } } public ConversionScore conversionScore(Class cls) { if (cls.equals(String.class) || StringBuffer.class.isAssignableFrom(cls)) return ConversionScore.exact; for (Class c : COMPATIBLE_CLASSES) { if (cls.equals(c)) return ConversionScore.compatible; } if (cls.isEnum()) { try { String elementValue = URLDecoder.decode(element.getStringValue(), DEFAULT_ENCODING); Enum.valueOf(cls, elementValue); return ConversionScore.compatible; } catch (IllegalArgumentException ex) { } catch (UnsupportedEncodingException ex) { } } return ConversionScore.nomatch; } public void marshal(OutputStream out) throws IOException { out.write(STRING_TAG_OPEN); out.write(URLEncoder.encode(value.toString(), DEFAULT_ENCODING).replace("+", "%20").getBytes()); out.write(STRING_TAG_CLOSE); } }