/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.click.util; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Member; | |
import java.math.BigDecimal; | |
import java.math.BigInteger; | |
import java.text.DateFormat; | |
import java.text.ParseException; | |
import java.util.Map; | |
import org.apache.commons.lang.Validate; | |
import ognl.OgnlOps; | |
import ognl.OgnlRuntime; | |
import ognl.TypeConverter; | |
/** | |
* Provides an request parameter OGNL TypeConverter class. | |
* <p/> | |
* This class is adapted from the OGNL <tt>DefaultTypeConverter</tt>, by | |
* Luke Blanshard and Drew Davidson, and provides additional Date conversion | |
* capabilities. | |
*/ | |
public class RequestTypeConverter implements TypeConverter { | |
// --------------------------------------------------------- Public Methods | |
/** | |
* Converts the given value to a given type. The OGNL context, target, | |
* member and name of property being set are given. This method should be | |
* able to handle conversion in general without any context, target, member | |
* or property name specified. | |
* | |
* @param context OGNL context under which the conversion is being done | |
* @param target target object in which the property is being set | |
* @param member member (Constructor, Method or Field) being set | |
* @param propertyName property name being set | |
* @param value value to be converted | |
* @param toType type to which value is converted | |
* @return Converted value of type toType or TypeConverter.NoConversionPossible | |
* to indicate that the conversion was not possible. | |
*/ | |
@SuppressWarnings("unchecked") | |
public Object convertValue(Map context, Object target, Member member, | |
String propertyName, Object value, Class toType) { | |
return convertValue(value, toType); | |
} | |
// ------------------------------------------------------ Protected Methods | |
/** | |
* Return the converted value for the given value object and target type. | |
* | |
* @param value the value object to convert | |
* @param toType the target class type to convert the value to | |
* @return a converted value into the specified type | |
*/ | |
protected Object convertValue(Object value, Class<?> toType) { | |
Object result = null; | |
if (value != null) { | |
// If array -> array then convert components of array individually | |
if (value.getClass().isArray() && toType.isArray()) { | |
Class<?> componentType = toType.getComponentType(); | |
result = | |
Array.newInstance(componentType, Array.getLength(value)); | |
for (int i = 0, icount = Array.getLength(value); i < icount; i++) { | |
Array.set(result, | |
i, | |
convertValue(Array.get(value, i), | |
componentType)); | |
} | |
} else { | |
if ((toType == Integer.class) || (toType == Integer.TYPE)) { | |
result = Integer.valueOf((int) OgnlOps.longValue(value)); | |
} else if ((toType == Double.class) || (toType == Double.TYPE)) { | |
result = new Double(OgnlOps.doubleValue(value)); | |
} else if ((toType == Boolean.class) || (toType == Boolean.TYPE)) { | |
result = Boolean.valueOf(value.toString()); | |
} else if ((toType == Byte.class) || (toType == Byte.TYPE)) { | |
result = Byte.valueOf((byte) OgnlOps.longValue(value)); | |
} else if ((toType == Character.class) || (toType == Character.TYPE)) { | |
result = Character.valueOf((char) OgnlOps.longValue(value)); | |
} else if ((toType == Short.class) || (toType == Short.TYPE)) { | |
result = Short.valueOf((short) OgnlOps.longValue(value)); | |
} else if ((toType == Long.class) || (toType == Long.TYPE)) { | |
result = Long.valueOf(OgnlOps.longValue(value)); | |
} else if ((toType == Float.class) || (toType == Float.TYPE)) { | |
result = new Float(OgnlOps.doubleValue(value)); | |
} else if (toType == BigInteger.class) { | |
result = OgnlOps.bigIntValue(value); | |
} else if (toType == BigDecimal.class) { | |
result = bigDecValue(value); | |
} else if (toType == String.class) { | |
result = OgnlOps.stringValue(value); | |
} else if (toType == java.util.Date.class) { | |
long time = getTimeFromDateString(value.toString()); | |
if (time > Long.MIN_VALUE) { | |
result = new java.util.Date(time); | |
} | |
} else if (toType == java.sql.Date.class) { | |
long time = getTimeFromDateString(value.toString()); | |
if (time > Long.MIN_VALUE) { | |
result = new java.sql.Date(time); | |
} | |
} else if (toType == java.sql.Time.class) { | |
long time = getTimeFromDateString(value.toString()); | |
if (time > Long.MIN_VALUE) { | |
result = new java.sql.Time(time); | |
} | |
} else if (toType == java.sql.Timestamp.class) { | |
long time = getTimeFromDateString(value.toString()); | |
if (time > Long.MIN_VALUE) { | |
result = new java.sql.Timestamp(time); | |
} | |
} | |
} | |
} else { | |
if (toType.isPrimitive()) { | |
result = OgnlRuntime.getPrimitiveDefaultValue(toType); | |
} | |
} | |
return result; | |
} | |
/** | |
* Return the time value in milliseconds of the given date value string, | |
* or Long.MIN_VALUE if the date could not be determined. | |
* | |
* @param value the date value string | |
* @return the time value in milliseconds or Long.MIN_VALUE if not determined | |
*/ | |
protected long getTimeFromDateString(String value) { | |
Validate.notNull(value, "Null value string"); | |
value = value.trim(); | |
if (value.length() == 0) { | |
return Long.MIN_VALUE; | |
} | |
if (isTimeValue(value)) { | |
return Long.parseLong(value); | |
} | |
java.util.Date date = createDateFromSqlString(value); | |
if (date != null) { | |
return date.getTime(); | |
} | |
try { | |
DateFormat format = DateFormat.getDateInstance(); | |
date = format.parse(value); | |
return date.getTime(); | |
} catch (ParseException pe) { | |
return Long.MIN_VALUE; | |
} | |
} | |
/** | |
* Return true if the given string value is a long time value. | |
* | |
* @param value the string value to test | |
* @return true if the given string value is a long time value. | |
*/ | |
protected boolean isTimeValue(String value) { | |
for (int i = 0, size = value.length(); i < size; i++) { | |
char aChar = value.charAt(i); | |
if (i == 0) { | |
if (!Character.isDigit(aChar) && aChar != '-') { | |
return false; | |
} | |
} else { | |
if (!Character.isDigit(aChar)) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
/** | |
* Return a new date object from the give SQL format date string, or null | |
* if the value is invalid. | |
* | |
* @param value the SQL format date string | |
* @return a new date object from the give SQL format date string | |
*/ | |
protected java.util.Date createDateFromSqlString(String value) { | |
if (value.length() != 10) { | |
return null; | |
} | |
for (int i = 0, size = value.length(); i < size; i++) { | |
char aChar = value.charAt(i); | |
if (!Character.isDigit(aChar) && aChar != '-') { | |
return null; | |
} | |
} | |
int firstDash = value.indexOf('-'); | |
int secondDash = value.indexOf('-', firstDash + 1); | |
if ((firstDash > 0) | |
& (secondDash > 0) | |
& (secondDash < value.length() - 1)) { | |
try { | |
int year = Integer.parseInt(value.substring(0, firstDash)) - 1900; | |
int month = Integer.parseInt(value.substring(firstDash + 1, secondDash)) - 1; | |
int day = Integer.parseInt(value.substring(secondDash + 1)); | |
return new java.util.Date(year, month, day); | |
} catch (NumberFormatException nfe) { | |
return null; | |
} | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Convert the given value into a BigDecimal. | |
* | |
* @param value the object to convert into a BigDecimal | |
* @return the converted BigDecimal value | |
*/ | |
private BigDecimal bigDecValue(Object value) { | |
if (value == null) { | |
return BigDecimal.valueOf(0L); | |
} | |
Class<?> c = value.getClass(); | |
if (c == BigDecimal.class) { | |
return (BigDecimal) value; | |
} | |
if (c == BigInteger.class) { | |
return new BigDecimal((BigInteger) value); | |
} | |
if (c == Boolean.class) { | |
return BigDecimal.valueOf(((Boolean) value).booleanValue() ? 1 : 0); | |
} | |
if (c == Character.class) { | |
return BigDecimal.valueOf(((Character) value).charValue()); | |
} | |
return new BigDecimal(value.toString().trim()); | |
} | |
} |