[jboss-cvs] jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper ...
Shane Bryzak
sbryzak at redhat.com
Tue Feb 27 17:15:24 EST 2007
User: sbryzak2
Date: 07/02/27 17:15:24
Added: src/remoting/org/jboss/seam/remoting/wrapper
BagWrapper.java BaseWrapper.java BeanWrapper.java
BooleanWrapper.java ConversionException.java
ConversionScore.java DateWrapper.java
MapWrapper.java NullWrapper.java NumberWrapper.java
StringWrapper.java Wrapper.java WrapperFactory.java
Log:
JBSEAM-915
Revision Changes Path
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/BagWrapper.java
Index: BagWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import org.dom4j.Element;
import org.hibernate.collection.PersistentCollection;
/**
* Wrapper for collections, arrays, etc.
*
* @author Shane Bryzak
*/
public class BagWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] BAG_TAG_OPEN = "<bag>".getBytes();
private static final byte[] BAG_TAG_CLOSE = "</bag>".getBytes();
private static final byte[] ELEMENT_TAG_OPEN = "<element>".getBytes();
private static final byte[] ELEMENT_TAG_CLOSE = "</element>".getBytes();
public void marshal(OutputStream out) throws IOException
{
out.write(BAG_TAG_OPEN);
// Fix to prevent uninitialized lazy loading in Hibernate
if (value instanceof PersistentCollection)
{
if (!((PersistentCollection) value).wasInitialized())
{
out.write(BAG_TAG_CLOSE);
return;
}
}
Collection vals = null;
// If the value is an array, convert it to a Collection
if (value.getClass().isArray())
{
vals = new ArrayList();
for (int i = 0; i < Array.getLength(value); i++)
vals.add(Array.get(value, i));
}
else if (Collection.class.isAssignableFrom(value.getClass()))
vals = (Collection) value;
else
throw new RuntimeException(String.format(
"Can not marshal object as bag: [%s]", value));
for (Object val : vals)
{
out.write(ELEMENT_TAG_OPEN);
context.createWrapperFromObject(val, path).marshal(out);
out.write(ELEMENT_TAG_CLOSE);
}
out.write(BAG_TAG_CLOSE);
}
@SuppressWarnings("unchecked")
public Object convert(Type type)
throws ConversionException
{
// First convert the elements in the bag to a List of Wrappers
List<Wrapper> vals = new ArrayList<Wrapper>();
for (Element e : (List<Element>) element.elements("element"))
vals.add(context.createWrapperFromElement((Element) e.elements().get(0)));
if (type instanceof Class && ((Class) type).isArray())
{
Class arrayType = ((Class) type).getComponentType();
value = Array.newInstance(arrayType, vals.size()); // Fix this
for (int i = 0; i < vals.size(); i++)
Array.set(value, i, vals.get(i).convert(arrayType));
}
else if (type instanceof Class && Collection.class.isAssignableFrom((Class) type))
{
try {
value = getConcreteClass( (Class) type).newInstance();
}
catch (Exception ex) {
throw new ConversionException(String.format(
"Could not create instance of target type [%s].", type));
}
for (Wrapper w : vals)
((Collection) value).add(w.convert(Object.class));
}
else if (type instanceof ParameterizedType &&
Collection.class.isAssignableFrom((Class) ((ParameterizedType) type).getRawType()))
{
Class rawType = (Class) ((ParameterizedType) type).getRawType();
Class genType = Object.class;
for (Type t : ((ParameterizedType) type).getActualTypeArguments())
{
if (t instanceof Class) // Take the first Class we find
{
genType = (Class) t;
break;
}
}
try {
value = getConcreteClass(rawType).newInstance();
}
catch (Exception ex) {
throw new ConversionException(String.format(
"Could not create instance of target type [%s].", rawType));
}
for (Wrapper w : vals)
((Collection) value).add(w.convert(genType));
}
return value;
}
private Class getConcreteClass(Class c)
{
if (c.isInterface())
{
// Support Set, Queue and (by default, and as a last resort) List
if (Set.class.isAssignableFrom(c))
return HashSet.class;
else if (Queue.class.isAssignableFrom(c))
return LinkedList.class;
else
return ArrayList.class;
}
else
return c;
}
/**
*
* @param cls Class
* @return ConversionScore
*/
public ConversionScore conversionScore(Class cls)
{
// There's no such thing as an exact match for a bag, so we'll just look for
// a compatible match
if (cls.isArray())
return ConversionScore.compatible;
if (cls.equals(Object.class))
return ConversionScore.compatible;
if (Collection.class.isAssignableFrom(cls))
return ConversionScore.compatible;
return ConversionScore.nomatch;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/BaseWrapper.java
Index: BaseWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import org.dom4j.Element;
import org.jboss.seam.remoting.CallContext;
/**
* Base class for all Wrapper implementations.
*
* @author Shane Bryzak
*/
public abstract class BaseWrapper implements Wrapper
{
/**
* The path of this object within the result object graph
*/
protected String path;
/**
* The call context
*/
protected CallContext context;
/**
* The DOM4J element containing the value
*/
protected Element element;
/**
* The wrapped value
*/
protected Object value;
/**
* Sets the path.
*
* @param path String
*/
public void setPath(String path)
{
this.path = path;
}
/**
* Sets the wrapped value
*
* @param value Object
*/
public void setValue(Object value)
{
this.value = value;
}
/**
* Returns the wrapped value
*
* @return Object
*/
public Object getValue()
{
return value;
}
/**
* Sets the call context
*/
public void setCallContext(CallContext context)
{
this.context = context;
}
/**
* Extracts a value from a DOM4J Element
*
* @param element Element
*/
public void setElement(Element element)
{
this.element = element;
}
/**
* Default implementation does nothing
*/
public void unmarshal() {}
/**
* Default implementation does nothing
*
* @param out OutputStream
* @throws IOException
*/
public void serialize(OutputStream out) throws IOException { }
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/BeanWrapper.java
Index: BeanWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import org.dom4j.Element;
import org.jboss.seam.Component;
import org.jboss.seam.Seam;
import org.jboss.seam.remoting.InterfaceGenerator;
import org.jboss.seam.util.Reflections;
/**
* @author Shane Bryzak
*/
public class BeanWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] REF_START_TAG_OPEN = "<ref id=\"".getBytes();
private static final byte[] REF_START_TAG_END = "\"/>".getBytes();
private static final byte[] BEAN_START_TAG_OPEN = "<bean type=\"".getBytes();
private static final byte[] BEAN_START_TAG_CLOSE = "\">".getBytes();
private static final byte[] BEAN_CLOSE_TAG = "</bean>".getBytes();
private static final byte[] MEMBER_START_TAG_OPEN = "<member name=\"".getBytes();
private static final byte[] MEMBER_START_TAG_CLOSE = "\">".getBytes();
private static final byte[] MEMBER_CLOSE_TAG = "</member>".getBytes();
@Override
public void setElement(Element element)
{
super.setElement(element);
String beanType = element.attributeValue("type");
Component component = Component.forName(beanType);
if (component != null)
{
value = component.newInstance();
}
else
{
try {
value = Reflections.classForName(beanType).newInstance();
}
catch (Exception ex) {
throw new RuntimeException("Could not unmarshal bean element: " + element.getText(), ex);
}
}
}
@Override
public void unmarshal()
{
List members = element.elements("member");
for (Element member : (List<Element>) members)
{
String name = member.attributeValue("name");
Wrapper w = context.createWrapperFromElement((Element) member.elementIterator().next());
Class cls = value.getClass();
// We're going to try a combination of ways to set the property value here
Method method = null;
Field field = null;
// First try to find the best matching method
String setter = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
ConversionScore score = ConversionScore.nomatch;
for (Method m : cls.getMethods())
{
if (setter.equals(m.getName()) && m.getParameterTypes().length == 1)
{
ConversionScore s = w.conversionScore(m.getParameterTypes()[0]);
if (s.getScore() > score.getScore())
{
method = m;
score = s;
}
}
}
// If we can't find a method, look for a matching field name
if (method == null)
{
while (field == null && !cls.equals(Object.class))
{
try
{
// First check the declared fields
field = cls.getDeclaredField(name);
}
catch (NoSuchFieldException ex)
{
// Couldn't find the field.. try the superclass
cls = cls.getSuperclass();
}
}
if (field == null)
{
throw new RuntimeException(String.format(
"Error while unmarshalling - property [%s] not found in class [%s]",
name, value.getClass().getName()));
}
}
// Now convert the field value to the correct target type
Object fieldValue = null;
try {
fieldValue = w.convert(method != null ? method.getGenericParameterTypes()[0] :
field.getGenericType());
}
catch (ConversionException ex) {
throw new RuntimeException("Could not convert value while unmarshaling", ex);
}
// If we have a setter method, invoke it
if (method != null)
{
try
{
method.invoke(value, fieldValue);
}
catch (Exception e)
{
throw new RuntimeException(String.format(
"Could not invoke setter method [%s]", method.getName()));
}
}
else
{
// Otherwise try to set the field value directly
boolean accessible = field.isAccessible();
try
{
if (!accessible)
field.setAccessible(true);
field.set(value, fieldValue);
}
catch (Exception ex)
{
throw new RuntimeException("Could not set field value.", ex);
}
finally
{
field.setAccessible(accessible);
}
}
}
}
public Object convert(Type type)
throws ConversionException
{
if (type instanceof Class && ((Class) type).isAssignableFrom(value.getClass()))
return value;
else
throw new ConversionException(String.format(
"Value [%s] cannot be converted to type [%s].", value, type));
}
public void marshal(OutputStream out)
throws IOException
{
context.addOutRef(this);
out.write(REF_START_TAG_OPEN);
out.write(Integer.toString(context.getOutRefs().indexOf(this)).getBytes());
out.write(REF_START_TAG_END);
}
@Override
public void serialize(OutputStream out)
throws IOException
{
serialize(out, null);
}
public void serialize(OutputStream out, List<String> constraints)
throws IOException
{
out.write(BEAN_START_TAG_OPEN);
Class cls = value.getClass();
/** @todo This is a hack to get the "real" class - find out if there is
an API method in CGLIB that can be used instead */
if (cls.getName().contains("EnhancerByCGLIB"))
cls = cls.getSuperclass();
String componentName = Seam.getComponentName(cls);
if (componentName != null)
out.write(componentName.getBytes());
else
out.write(cls.getName().getBytes());
out.write(BEAN_START_TAG_CLOSE);
for (String propertyName : InterfaceGenerator.getAccessibleProperties(cls))
{
String fieldPath = path != null && path.length() > 0 ? String.format("%s.%s", path, propertyName) : propertyName;
// Also exclude fields listed using wildcard notation: [componentName].fieldName
String wildCard = String.format("[%s].%s", componentName != null ? componentName : cls.getName(), propertyName);
if (constraints == null || (!constraints.contains(fieldPath) && !constraints.contains(wildCard)))
{
out.write(MEMBER_START_TAG_OPEN);
out.write(propertyName.getBytes());
out.write(MEMBER_START_TAG_CLOSE);
Field f = null;
try
{
f = cls.getField(propertyName);
}
catch (NoSuchFieldException ex) { }
boolean accessible = false;
try
{
// Temporarily set the field's accessibility so we can read it
if (f != null)
{
accessible = f.isAccessible();
f.setAccessible(true);
context.createWrapperFromObject(f.get(value),
fieldPath).marshal(out);
}
else
{
Method accessor = null;
try
{
accessor = cls.getMethod(String.format("get%s%s",
Character.toUpperCase(propertyName.charAt(0)),
propertyName.substring(1)));
}
catch (NoSuchMethodException ex)
{
try
{
accessor = cls.getMethod(String.format("is%s%s",
Character.toUpperCase(propertyName.charAt(0)),
propertyName.substring(1)));
}
catch (NoSuchMethodException ex2)
{
// uh oh... continue with the next one
continue;
}
}
try
{
context.createWrapperFromObject(accessor.invoke(value), fieldPath).
marshal(out);
}
catch (InvocationTargetException ex)
{
throw new RuntimeException(String.format(
"Failed to read property [%s] for object [%s]",
propertyName, value));
}
}
}
catch (IllegalAccessException ex)
{
throw new RuntimeException("Error reading value from field.");
}
finally
{
if (f != null)
f.setAccessible(accessible);
}
out.write(MEMBER_CLOSE_TAG);
}
}
out.write(BEAN_CLOSE_TAG);
}
public ConversionScore conversionScore(Class cls) {
if (cls.equals(value.getClass()))
return ConversionScore.exact;
else if (cls.isAssignableFrom(value.getClass()) || cls.equals(Object.class))
return ConversionScore.compatible;
else
return ConversionScore.nomatch;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/BooleanWrapper.java
Index: BooleanWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
/**
* @author Shane Bryzak
*/
public class BooleanWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] BOOL_TAG_OPEN = "<bool>".getBytes();
private static final byte[] BOOL_TAG_CLOSE = "</bool>".getBytes();
public void marshal(OutputStream out) throws IOException
{
out.write(BOOL_TAG_OPEN);
out.write(((Boolean) value).toString().getBytes());
out.write(BOOL_TAG_CLOSE);
}
public Object convert(Type type)
throws ConversionException
{
if (type.equals(Boolean.class) || type.equals(Object.class))
value = Boolean.valueOf(element.getStringValue());
else if (type.equals(Boolean.TYPE))
value = Boolean.parseBoolean(element.getStringValue());
else
throw new ConversionException(String.format(
"Parameter [%s] cannot be converted to type [%s].",
element.getStringValue(), type));
return value;
}
public ConversionScore conversionScore(Class cls)
{
if (cls.equals(Boolean.class) || cls.equals(Boolean.TYPE))
return ConversionScore.exact;
else if (cls.equals(Object.class))
return ConversionScore.compatible;
else
return ConversionScore.nomatch;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/ConversionException.java
Index: ConversionException.java
===================================================================
package org.jboss.seam.remoting.wrapper;
/**
* Thrown for an invalid conversion.
*
* @author Shane Bryzak
*/
public class ConversionException extends Exception
{
private static final long serialVersionUID = 5584559762846984501L;
public ConversionException(String message)
{
super(message);
}
public ConversionException(String message, Throwable cause)
{
super(message, cause);
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/ConversionScore.java
Index: ConversionScore.java
===================================================================
package org.jboss.seam.remoting.wrapper;
/**
*
* @author Shane Bryzak
*/
public enum ConversionScore
{
nomatch(0),
compatible(1),
exact(2);
private int score;
ConversionScore(int score)
{
this.score = score;
}
public int getScore()
{
return score;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/DateWrapper.java
Index: DateWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Handles date conversions
*
* @author Shane Bryzak
*/
public class DateWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] DATE_TAG_OPEN = "<date>".getBytes();
private static final byte[] DATE_TAG_CLOSE = "</date>".getBytes();
private static final DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
public void marshal(OutputStream out) throws IOException
{
out.write(DATE_TAG_OPEN);
out.write(df.format(value).getBytes());
out.write(DATE_TAG_CLOSE);
}
public Object convert(Type type)
throws ConversionException
{
if ((type instanceof Class && Date.class.isAssignableFrom((Class) type)) ||
type.equals(Object.class))
{
try {
value = df.parse(element.getStringValue());
}
catch (ParseException ex) {
throw new ConversionException(String.format(
"Date value [%s] is not in a valid format.", element.getStringValue()));
}
}
else
throw new ConversionException(String.format(
"Value [%s] cannot be converted to type [%s].", element.getStringValue(),
type));
return value;
}
public ConversionScore conversionScore(Class cls)
{
if (Date.class.isAssignableFrom(cls))
return ConversionScore.exact;
else if (cls.equals(Object.class))
return ConversionScore.compatible;
else
return ConversionScore.nomatch;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/MapWrapper.java
Index: MapWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Element;
/**
* @author Shane Bryzak
*/
public class MapWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] MAP_TAG_OPEN = "<map>".getBytes();
private static final byte[] MAP_TAG_CLOSE = "</map>".getBytes();
private static final byte[] ELEMENT_TAG_OPEN = "<element>".getBytes();
private static final byte[] ELEMENT_TAG_CLOSE = "</element>".getBytes();
private static final byte[] KEY_TAG_OPEN = "<k>".getBytes();
private static final byte[] KEY_TAG_CLOSE = "</k>".getBytes();
private static final byte[] VALUE_TAG_OPEN = "<v>".getBytes();
private static final byte[] VALUE_TAG_CLOSE = "</v>".getBytes();
public void marshal(OutputStream out) throws IOException
{
out.write(MAP_TAG_OPEN);
Map m = (Map) this.value;
for (Object key : m.keySet())
{
out.write(ELEMENT_TAG_OPEN);
out.write(KEY_TAG_OPEN);
context.createWrapperFromObject(key, String.format("%s[key]", path)).marshal(out);
out.write(KEY_TAG_CLOSE);
out.write(VALUE_TAG_OPEN);
context.createWrapperFromObject(m.get(key), String.format("%s[value]", path)).marshal(out);
out.write(VALUE_TAG_CLOSE);
out.write(ELEMENT_TAG_CLOSE);
}
out.write(MAP_TAG_CLOSE);
}
public Object convert(Type type)
throws ConversionException
{
Class typeClass = null;
Type keyType = null;
Type valueType = null;
// Either the type should be a generified Map
if (type instanceof ParameterizedType &&
Map.class.isAssignableFrom((Class) ((ParameterizedType) type).getRawType()))
{
typeClass = (Class) ((ParameterizedType) type).getRawType();
for (Type t : ((ParameterizedType) type).getActualTypeArguments())
{
if (keyType == null)
keyType = t;
else
{
valueType = t;
break;
}
}
}
// Or a non-generified Map
else if (type instanceof Class && Map.class.isAssignableFrom((Class) type))
{
if (!((Class) type).isInterface())
typeClass = (Class) type;
keyType = Object.class;
valueType = Object.class;
}
// If it's neither, throw an exception
else
throw new ConversionException(String.format(
"Cannot convert value to type [%s]", type));
// If we don't have a concrete type, default to creating a HashMap
if (typeClass == null || typeClass.isInterface())
value = new HashMap();
else
{
try {
// Otherwise create an instance of the concrete type
value = ( (Class) type).newInstance();
}
catch (Exception ex) {
throw new ConversionException(String.format(
"Could not create value of type [%s]", type));
}
}
for (Element e : (List<Element>) element.elements("element"))
{
Element keyElement = (Element) e.element("k").elementIterator().next();
Element valueElement = (Element) e.element("v").elementIterator().next();
((Map) value).put(
context.createWrapperFromElement(keyElement).convert(keyType),
context.createWrapperFromElement(valueElement).convert(valueType));
}
return value;
}
public ConversionScore conversionScore(Class cls)
{
if (Map.class.isAssignableFrom(cls))
return ConversionScore.exact;
if (cls.equals(Object.class))
return ConversionScore.compatible;
return ConversionScore.nomatch;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/NullWrapper.java
Index: NullWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
/**
* @author Shane Bryzak
*/
public class NullWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] NULL_WRAPPER_TAG = "<null/>".getBytes();
public void marshal(OutputStream out) throws IOException
{
out.write(NULL_WRAPPER_TAG);
}
public Object convert(Type type)
throws ConversionException
{
return null;
}
public ConversionScore conversionScore(Class cls)
{
return ConversionScore.compatible;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/NumberWrapper.java
Index: NumberWrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
/**
* Int wrapper class.
*
* @author Shane Bryzak
*/
public class NumberWrapper extends BaseWrapper implements Wrapper
{
private static final byte[] NUMBER_TAG_OPEN = "<number>".getBytes();
private static final byte[] NUMBER_TAG_CLOSE = "</number>".getBytes();
public Object convert(Type type)
throws ConversionException
{
String val = element.getStringValue().trim();
if (type.equals(Short.class))
value = !"".equals(val) ? Short.valueOf(val) : null;
else if (type.equals(Short.TYPE))
value = Short.parseShort(val);
else if (type.equals(Integer.class))
value = !"".equals(val) ? Integer.valueOf(val) : null;
else if (type.equals(Integer.TYPE))
value = Integer.parseInt(val);
else if (type.equals(Long.class) || type.equals(Object.class))
value = !"".equals(val) ? Long.valueOf(val) : null;
else if (type.equals(Long.TYPE))
value = Long.parseLong(val);
else if (type.equals(Float.class))
value = !"".equals(val) ? Float.valueOf(val) : null;
else if (type.equals(Float.TYPE))
value = Float.parseFloat(val);
else if (type.equals(Double.class))
value = !"".equals(val) ? Double.valueOf(val) : null;
else if (type.equals(Double.TYPE))
value = Double.parseDouble(val);
else if (type.equals(Byte.class))
value = !"".equals(val) ? Byte.valueOf(val) : null;
else if (type.equals(Byte.TYPE))
value = Byte.parseByte(val);
else if (type.equals(String.class))
value = val;
else
throw new ConversionException(String.format(
"Value [%s] cannot be converted to type [%s].", element.getStringValue(),
type));
return value;
}
/**
*
* @param out OutputStream
* @throws IOException
*/
public void marshal(OutputStream out)
throws IOException
{
out.write(NUMBER_TAG_OPEN);
out.write(value.toString().getBytes());
out.write(NUMBER_TAG_CLOSE);
}
/**
* Allow conversions to either Integer or String.
*
* @param cls Class
* @return ConversionScore
*/
public ConversionScore conversionScore(Class cls)
{
if (cls.equals(Integer.class) || cls.equals(Integer.TYPE))
return ConversionScore.exact;
if (cls.equals(String.class) || cls.equals(Object.class))
return ConversionScore.compatible;
return ConversionScore.nomatch;
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/StringWrapper.java
Index: StringWrapper.java
===================================================================
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);
}
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/Wrapper.java
Index: Wrapper.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
import org.dom4j.Element;
import org.jboss.seam.remoting.CallContext;
/**
* Acts as a wrapper around parameter values passed within an AJAX call.
*
* @author Shane Bryzak
*/
public interface Wrapper
{
/**
* Sets the path of the wrapped object within the resulting object graph
*
* @param path String
*/
public void setPath(String path);
public void setCallContext(CallContext context);
/**
* Extracts a value from a DOM4J Element
*
* @param element Element
*/
public void setElement(Element element);
/**
*
* @param value Object
*/
public void setValue(Object value);
/**
*
* @return Object
*/
public Object getValue();
/**
*
*/
public void unmarshal();
/**
* Convert the wrapped parameter value to the specified target class.
*
*/
public Object convert(Type type) throws ConversionException;
public void marshal(OutputStream out) throws IOException;
public void serialize(OutputStream out) throws IOException;
/**
* Returns a score indicating whether this parameter value can be converted
* to the specified type. This helper method is used to determine which
* (possibly overloaded) method of a component can/should be called.
*
* 0 - Cannot be converted
* 1 - Can be converted to this type
* 2 - Param is this exact type
*
*/
public ConversionScore conversionScore(Class cls);
}
1.1 date: 2007/02/27 22:15:24; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/wrapper/WrapperFactory.java
Index: WrapperFactory.java
===================================================================
package org.jboss.seam.remoting.wrapper;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Shane Bryzak
*/
public class WrapperFactory
{
/**
* Singleton instance.
*/
private static final WrapperFactory factory = new WrapperFactory();
/**
* A registry of wrapper types
*/
private Map<String,Class> wrapperRegistry = new HashMap<String,Class>();
private Map<Class,Class> classRegistry = new HashMap<Class,Class>();
/**
* Private constructor
*/
private WrapperFactory()
{
// Register the defaults
registerWrapper("str", StringWrapper.class);
registerWrapper("bool", BooleanWrapper.class);
registerWrapper("bean", BeanWrapper.class);
registerWrapper("number", NumberWrapper.class);
registerWrapper("null", NullWrapper.class);
registerWrapper("bag", BagWrapper.class);
registerWrapper("map", MapWrapper.class);
registerWrapper("date", DateWrapper.class);
// String types
registerWrapperClass(String.class, StringWrapper.class);
registerWrapperClass(StringBuilder.class, StringWrapper.class);
registerWrapperClass(StringBuffer.class, StringWrapper.class);
registerWrapperClass(Character.class, StringWrapper.class);
// Big numbers are handled by StringWrapper
registerWrapperClass(BigDecimal.class, StringWrapper.class);
registerWrapperClass(BigInteger.class, StringWrapper.class);
// Number types
registerWrapperClass(Integer.class, NumberWrapper.class);
registerWrapperClass(Long.class, NumberWrapper.class);
registerWrapperClass(Short.class, NumberWrapper.class);
registerWrapperClass(Double.class, NumberWrapper.class);
registerWrapperClass(Float.class, NumberWrapper.class);
registerWrapperClass(Byte.class, NumberWrapper.class);
}
public void registerWrapper(String type, Class wrapperClass)
{
wrapperRegistry.put(type, wrapperClass);
}
public void registerWrapperClass(Class cls, Class wrapperClass)
{
classRegistry.put(cls, wrapperClass);
}
public static WrapperFactory getInstance()
{
return factory;
}
public Wrapper createWrapper(String type)
{
Class wrapperClass = wrapperRegistry.get(type);
if (wrapperClass != null)
{
try {
Wrapper wrapper = (Wrapper) wrapperClass.newInstance();
return wrapper;
}
catch (Exception ex) { }
}
throw new RuntimeException(String.format("Failed to create wrapper for type: %s",
type));
}
public Wrapper getWrapperForObject(Object obj)
{
if (obj == null)
return new NullWrapper();
Wrapper w = null;
if (Map.class.isAssignableFrom(obj.getClass()))
w = new MapWrapper();
else if (obj.getClass().isArray() || Collection.class.isAssignableFrom(obj.getClass()))
w = new BagWrapper();
else if (obj.getClass().equals(Boolean.class) || obj.getClass().equals(Boolean.TYPE))
w = new BooleanWrapper();
else if (obj.getClass().isEnum())
w = new StringWrapper();
else if (Date.class.isAssignableFrom(obj.getClass()))
w = new DateWrapper();
else if (classRegistry.containsKey(obj.getClass()))
{
try
{
w = (Wrapper) classRegistry.get(obj.getClass()).newInstance();
}
catch (Exception ex)
{
throw new RuntimeException("Failed to create wrapper instance.");
}
}
else
w = new BeanWrapper();
w.setValue(obj);
return w;
}
}
More information about the jboss-cvs-commits
mailing list