您的位置:首页 > 编程语言 > Java开发

Struts使用BeanUtils提供的数据类型转换器

2009-02-25 17:09 411 查看
关键字: struts beanutils converter

Struts版本——1.2.9

BeanUtils版本——1.7.0

在使用Struts开发的应用中,当请求转交到Action时,如果有关联这个Action的ActionForm,Struts会用请求参数填充ActionForm里相应的字段。

由于ActionForm字段的数据类型是在应用运行前写死的,请求参数是在应用运行后才能确定的,所以它们之间存在数据类型转换的问题。

Struts在用请求参数填充ActionForm字段时,不论它们数据类型是否一致,都会根据ActionForm字段的数据类型,使用相应的数据类型转换器将请求参数转换成和ActionForm字段相同的数据类型,然后调用字段对应的setter方法来填充字段。

Struts没有自己实现这些转换器,而是使用Apache Commons BeanUtils提供的一系列转换器,在org.apache.commons.beanutils.ConvertUtilsBean类的deregister()方法里,可以看到这些转换器的注册过程,代码如下:

/**

* Remove all registered {@link Converter}s, and re-establish the

* standard Converters.

*/

public void deregister() {

boolean booleanArray[] = new boolean[0];

byte byteArray[] = new byte[0];

char charArray[] = new char[0];

double doubleArray[] = new double[0];

float floatArray[] = new float[0];

int intArray[] = new int[0];

long longArray[] = new long[0];

short shortArray[] = new short[0];

String stringArray[] = new String[0];

converters.clear();

register(BigDecimal.class, new BigDecimalConverter());

register(BigInteger.class, new BigIntegerConverter());

register(Boolean.TYPE, new BooleanConverter(defaultBoolean));

register(Boolean.class, new BooleanConverter(defaultBoolean));

register(booleanArray.getClass(),

new BooleanArrayConverter(booleanArray));

register(Byte.TYPE, new ByteConverter(defaultByte));

register(Byte.class, new ByteConverter(defaultByte));

register(byteArray.getClass(),

new ByteArrayConverter(byteArray));

register(Character.TYPE,

new CharacterConverter(defaultCharacter));

register(Character.class,

new CharacterConverter(defaultCharacter));

register(charArray.getClass(),

new CharacterArrayConverter(charArray));

register(Class.class, new ClassConverter());

register(Double.TYPE, new DoubleConverter(defaultDouble));

register(Double.class, new DoubleConverter(defaultDouble));

register(doubleArray.getClass(),

new DoubleArrayConverter(doubleArray));

register(Float.TYPE, new FloatConverter(defaultFloat));

register(Float.class, new FloatConverter(defaultFloat));

register(floatArray.getClass(),

new FloatArrayConverter(floatArray));

register(Integer.TYPE, new IntegerConverter(defaultInteger));

register(Integer.class, new IntegerConverter(defaultInteger));

register(intArray.getClass(),

new IntegerArrayConverter(intArray));

register(Long.TYPE, new LongConverter(defaultLong));

register(Long.class, new LongConverter(defaultLong));

register(longArray.getClass(),

new LongArrayConverter(longArray));

register(Short.TYPE, new ShortConverter(defaultShort));

register(Short.class, new ShortConverter(defaultShort));

register(shortArray.getClass(),

new ShortArrayConverter(shortArray));

register(String.class, new StringConverter());

register(stringArray.getClass(),

new StringArrayConverter(stringArray));

register(Date.class, new SqlDateConverter());

register(Time.class, new SqlTimeConverter());

register(Timestamp.class, new SqlTimestampConverter());

register(File.class, new FileConverter());

register(URL.class, new URLConverter());

}

对数据的类型转换实际上就是调用相应转换器类的convert()方法,该方法在Converter接口中定义,上面的转换器类都直接或间接的实现了该接口,方法定义如下:

/**

* Convert the specified input object into an output object of the

* specified type.

*

* @param type Data type to which this value should be converted

* @param value The input value to be converted

*

* @exception ConversionException if conversion cannot be performed

* successfully

*/

public Object convert(Class type, Object value);

根据各转换器类convert()方法代码类似程度,可以把它们分为3类。下面详细说说它们的convert()方法的实现。

第1类:StringConverter

StringConverter.java

/**

* Convert the specified input object into an output object of the

* specified type.

*

* @param type Data type to which this value should be converted

* @param value The input value to be converted

*

* @exception ConversionException if conversion cannot be performed

* successfully

*/

public Object convert(Class type, Object value) {

if (value == null) {

return ((String) null);

} else {

return (value.toString());

}

}

它的实现最简单,如果参数value为null,返回null;否则,返回value.toString()。

第2类:BigDecimalConverter、BigIntegerConverter、BooleanConverter、ByteConverter、CharacterConverter、DoubleConverter、FloatConverter、IntegerConverter、LongConverter、ShortConverter、SqlDateConverter、SqlTimeConverter、SqlTimestampConverter、FileConverter、URLConverter、ClassConverter

它们对convert()方法的实现很类似,可分为3步。下面仅列出IntegerConverter的convert()方法代码,以便给后面的纯文字叙述做个参考。

IntegerConverter.java

/**

* Convert the specified input object into an output object of the

* specified type.

*

* @param type Data type to which this value should be converted

* @param value The input value to be converted

*

* @exception ConversionException if conversion cannot be performed

* successfully

*/

public Object convert(Class type, Object value) {

if (value == null) {

if (useDefault) {

return (defaultValue);

} else {

throw new ConversionException("No value specified");

}

}

if (value instanceof Integer) {

return (value);

} else if(value instanceof Number) {

return new Integer(((Number)value).intValue());

}

try {

return (new Integer(value.toString()));

} catch (Exception e) {

if (useDefault) {

return (defaultValue);

} else {

throw new ConversionException(e);

}

}

}

第1步:如果参数value为null,根据类字段useDefault的值,要么返回类字段defaultValue的值,要么抛出ConversionException。

第2步:如果参数value instanceof目标类型,则返回value。

其中,ByteConverter、DoubleConverter、FloatConverter、IntegerConverter、LongConverter、ShortConverter还会判断如果参数value instanceof java.lang.Number,则把value转换成Number,调用Number相应的XXXValue()方法返回值。

第3步:如果参数value都不满足前面两步,则分别做如下的转换:

SqlDateConverter、SqlTimeConverter、SqlTimestampConverter调用XXX.valueOf(value.toString())来转换。其它除了BooleanConverter外的Converter使用new XXX(value.toString())来转换。XXX表示转换的目标类。BooleanConverter判断value.toString()的值,如果是"yes"、"y"、"true"、"on"、"1"之一,返回Boolean.TRUE;如果是"no"、"n"、"false"、"off"、"0"之一,返回Boolean.FALSE;如果都不是,按照第1步中如果参数value为null同样方式处理。

如果在这个第3步中抛出异常,按照第1步中如果参数value为null同样方式处理。

第3类:BooleanArrayConverter、ByteArrayConverter、CharacterArrayConverter、DoubleArrayConverter、FloatArrayConverter、IntegerArrayConverter、LongArrayConverter、ShortArrayConverter、StringArrayConverter

从名字就可看出,这些都是转换到数组类型的,这里要注意的是,并不是包装类数组,而是基本数据类型数组。它们都继承自org.apache.commons.beanutils.converters.AbstractArrayConverter,这是个抽象类,它实现了Converter接口。它们的convert()方法实现可分为4步。下面仅列出IntegerArrayConverter的convert()方法代码,以便给后面的纯文字叙述做个参考。

IntegerArrayConverter.java

/**

* Convert the specified input object into an output object of the

* specified type.

*

* @param type Data type to which this value should be converted

* @param value The input value to be converted

*

* @exception ConversionException if conversion cannot be performed

* successfully

*/

public Object convert(Class type, Object value) {

// Deal with a null value

if (value == null) {

if (useDefault) {

return (defaultValue);

} else {

throw new ConversionException("No value specified");

}

}

// Deal with the no-conversion-needed case

if (model.getClass() == value.getClass()) {

return (value);

}

// Deal with input value as a String array

if (strings.getClass() == value.getClass()) {

try {

String values[] = (String[]) value;

int results[] = new int[values.length];

for (int i = 0; i < values.length; i++) {

results[i] = Integer.parseInt(values[i]);

}

return (results);

} catch (Exception e) {

if (useDefault) {

return (defaultValue);

} else {

throw new ConversionException(value.toString(), e);

}

}

}

// Parse the input value as a String into elements

// and convert to the appropriate type

try {

List list = parseElements(value.toString());

int results[] = new int[list.size()];

for (int i = 0; i < results.length; i++) {

results[i] = Integer.parseInt((String) list.get(i));

}

return (results);

} catch (Exception e) {

if (useDefault) {

return (defaultValue);

} else {

throw new ConversionException(value.toString(), e);

}

}

}

第1步:和第2类中的第1步一样。

第2步:如果参数value的类型和转换器类的model字段的类型相同,直接返回value。model字段的类型也就是该转换器类对应的目标类类型,比如LongArrayConverter里的model是long[]。

第3步:除StringArrayConverter外,如果参数value的类型和AbstractArrayConverter类的strings字段的类型相同,也就是String[],则把value转换成String[]类型,循环对其中的每个String做如下转换:

ByteArrayConverter、DoubleArrayConverter、FloatArrayConverter、IntegerArrayConverter、LongArrayConverter、ShortArrayConverter使用对应包装类的parseXXX()方法;BooleanArrayConverter同第2类中第3步里BooleanConverter的处理方式;CharacterArrayConverter使用String.charAt(0)。

对于StringArrayConverter,第2步就做了这个判断了。所以第3步它判断的是如果参数value的类型和它的ints字段的类型相同,也就是int[],则value转换成int[]类型,循环对其中的每个int使用Integer.toString(int)转换。

返回转换后的新数组。

第4步:如果参数value都不满足上面几步的条件,则以value.toString()做为参数,调用AbstractArrayConverter的parseElements方法,得到一个List,其中的每个元素都是String。然后除StringArrayConverter外的其它Converter,按照与第3步中处理String[]的相同方式来处理List。StringArrayConverter则更简单,直接把List里的元素转到数组里返回。

下面是parseElements()方法的代码:

AbstractArrayConverter.java

/**

* Parse an incoming String of the form similar to an array initializer

* in the Java language into a List individual Strings

* for each element, according to the following rules.

*

* The string must have matching '{' and '}' delimiters around

* a comma-delimited list of values.

* Whitespace before and after each element is stripped.

* If an element is itself delimited by matching single or double

* quotes, the usual rules for interpreting a quoted String apply.

* @param svalue String value to be parsed

*

* @exception ConversionException if the syntax of svalue

* is not syntactically valid

* @exception NullPointerException if svalue

* is null

*/

protected List parseElements(String svalue) {

// Validate the passed argument

if (svalue == null) {

throw new NullPointerException();

}

// Trim any matching '{' and '}' delimiters

svalue = svalue.trim();

if (svalue.startsWith("{") && svalue.endsWith("}")) {

svalue = svalue.substring(1, svalue.length() - 1);

}

try {

// Set up a StreamTokenizer on the characters in this String

StreamTokenizer st =

new StreamTokenizer(new StringReader(svalue));

st.whitespaceChars(',',','); // Commas are delimiters

st.ordinaryChars('0', '9'); // Needed to turn off numeric flag

st.ordinaryChars('.', '.');

st.ordinaryChars('-', '-');

st.wordChars('0', '9'); // Needed to make part of tokens

st.wordChars('.', '.');

st.wordChars('-', '-');

// Split comma-delimited tokens into a List

ArrayList list = new ArrayList();

while (true) {

int ttype = st.nextToken();

if ((ttype == StreamTokenizer.TT_WORD) ||

(ttype > 0)) {

list.add(st.sval);

} else if (ttype == StreamTokenizer.TT_EOF) {

break;

} else {

throw new ConversionException

("Encountered token of type " + ttype);

}

}

// Return the completed list

return (list);

} catch (IOException e) {

throw new ConversionException(e);

}

}

方法注释里指出,它要求参数svalue是形如“{abc,def,ghi}”的字符串,使用逗号对svalue进行分隔,将分隔后的元素放到List里返回。

在这段代码的try块里,首先构造一个java.io.StreamTokenizer,设置逗号做为分隔符,再将0到9、负号、小数点这些字符设置为普通字符,因为默认的StreamTokenizer会将这些这些字符组成的字符串转换成double类型,而在这里不需要这个功能。然后使用StreamTokenizer的方式分隔svalue,将分隔的元素放到List里返回。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐