/*
* Copyright 2013 The Solmix Project
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.commons.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author solmix.f@gmail.com
* @version $Id$ 2014年8月14日
*/
public class TransformUtils
{
public static interface Transformer
{
public abstract Object transform(Object obj) throws Exception;
}
private static final Logger log = LoggerFactory.getLogger(TransformUtils.class.getName());
public static <T> T transformType(Class<T> targetType, Object value)
throws Exception {
if (targetType == null)
return null;
if (value == null)
return null;
if (targetType.isInstance(value))
return (T) value;
if ((value instanceof String) && "".equals(value)
&& Number.class.isAssignableFrom(targetType))
return null;
Transformer transformer = (Transformer) defaultTransformers.get(targetType);
if (transformer != null)
return (T) transformer.transform(value);
if (targetType.isEnum())
return (T) transformEnum(value, targetType);
if ((value instanceof Map) && !targetType.isPrimitive()
&& !targetType.isInterface() && !targetType.isArray()) {
Object instance = targetType.newInstance();
try {
DataUtils.setProperties((Map) value, instance);
return (T) instance;
} catch (Exception ee) {
log.debug((new StringBuilder()).append(
"Tried to convert inbound nested Map to: ").append(
targetType.getName()).append(
" but DataTools.setProperties() on instantiated class failed").append(
" with the following error: ").append(ee.getMessage()).toString());
}
}
if (!targetType.isPrimitive() && !targetType.isEnum()) {
Class<?> types[] = { value.getClass() };
Constructor<?> constructor = targetType.getConstructor(types);
Object arguments[] = { value };
return (T) constructor.newInstance(arguments);
}
if (!targetType.isPrimitive()
&& (targetType.isInterface() || Modifier.isAbstract(targetType.getModifiers())))
log.warn((new StringBuilder()).append(
"Impossible to convert to target type ").append(
targetType.getName()).append(" - it is not a concrete class").toString());
throw new IllegalArgumentException(
(new StringBuilder()).append("Can't convert value of type ").append(
value.getClass().getName()).append(" to target type ").append(
targetType.getName()).toString());
}
public static Object transformValue(Object value, Class<?> targetType) {
if (value == null)
return null;
Class<?> valueClass = value.getClass();
if (Boolean.TYPE.equals(targetType))
targetType = java.lang.Boolean.class;
if (Byte.TYPE.equals(targetType))
targetType = java.lang.Byte.class;
if (Short.TYPE.equals(targetType))
targetType = java.lang.Short.class;
if (Integer.TYPE.equals(targetType))
targetType = java.lang.Integer.class;
if (Long.TYPE.equals(targetType))
targetType = java.lang.Long.class;
if (Float.TYPE.equals(targetType))
targetType = java.lang.Float.class;
if (Double.TYPE.equals(targetType))
targetType = java.lang.Double.class;
if (Character.TYPE.equals(targetType))
targetType = java.lang.Character.class;
if (targetType.isInstance(value))
return value;
if (java.lang.Boolean.class.equals(targetType)) {
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return n.signum() != 0 ? Boolean.TRUE : Boolean.FALSE;
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
if (c == 'T' || c == 't' || c == 'Y' || c == 'y')
return Boolean.TRUE;
else
return Boolean.FALSE;
}
if (java.lang.String.class.isAssignableFrom(valueClass)) {
String s = value.toString();
if ("t".equalsIgnoreCase(s) || "y".equalsIgnoreCase(s)
|| "true".equalsIgnoreCase(s)
|| "false".equalsIgnoreCase(s))
return Boolean.TRUE;
else
return Boolean.FALSE;
}
} else if (java.lang.Byte.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Byte.valueOf((byte) (Boolean.TRUE.equals(value) ? 1 : 0));
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Byte.valueOf(n.byteValue());
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
return Byte.valueOf((byte) c);
}
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return Byte.valueOf(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException((new StringBuilder()).append(
"Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
} else if (java.lang.Short.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Short.valueOf((short) (Boolean.TRUE.equals(value) ? 1
: 0));
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Short.valueOf(n.shortValue());
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
return Short.valueOf((short) c);
}
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return Short.valueOf(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException((new StringBuilder()).append(
"Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
} else if (java.lang.Integer.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Integer.valueOf(Boolean.TRUE.equals(value) ? 1 : 0);
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Integer.valueOf(n.intValue());
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
return Integer.valueOf(c);
}
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return Integer.valueOf(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException((new StringBuilder()).append(
"Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
} else if (java.lang.Long.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Long.valueOf(Boolean.TRUE.equals(value) ? 1 : 0);
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Long.valueOf(n.longValue());
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
return Long.valueOf(c);
}
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return Long.valueOf(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException((new StringBuilder()).append(
"Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return Long.valueOf(((Date) value).getTime());
} else if (java.lang.Float.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Float.valueOf(Boolean.TRUE.equals(value) ? 1 : 0);
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Float.valueOf(n.floatValue());
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
return Float.valueOf(c);
}
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return Float.valueOf(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException((new StringBuilder()).append(
"Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return Float.valueOf(((Date) value).getTime());
} else if (java.lang.Double.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Double.valueOf(Boolean.TRUE.equals(value) ? 1 : 0);
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Double.valueOf(n.doubleValue());
}
if (java.lang.Character.class.isAssignableFrom(valueClass)) {
char c = ((Character) value).charValue();
return Double.valueOf(c);
}
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return Double.valueOf(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException((new StringBuilder()).append(
"Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return Double.valueOf(((Date) value).getTime());
} else if (java.lang.Character.class.equals(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Character.valueOf(Boolean.TRUE.equals(value) ? 't' : 'f');
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return Character.valueOf((char) n.intValue());
}
if (java.lang.String.class.isAssignableFrom(valueClass)) {
if ("".equals(value.toString()))
return Character.valueOf('\0');
value.toString().charAt(0);
}
} else if (targetType.isEnum()) {
return transformEnum(value, targetType);
} else {
if (java.lang.String.class.isAssignableFrom(targetType))
return value.toString();
if (java.math.BigInteger.class.isAssignableFrom(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Boolean.TRUE.equals(value) ? BigInteger.ONE
: BigInteger.ZERO;
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return n.toBigInteger();
}
if (java.lang.Character.class.isAssignableFrom(valueClass))
return BigInteger.valueOf(((Character) value).charValue());
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return new BigInteger(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(
value.toString()).append("' of type '").append(
valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return BigInteger.valueOf(((Date) value).getTime());
} else if (java.math.BigDecimal.class.isAssignableFrom(targetType)) {
if (java.lang.Boolean.class.isAssignableFrom(valueClass))
return Boolean.TRUE.equals(value) ? BigDecimal.ONE
: BigDecimal.ZERO;
if (java.lang.Number.class.isAssignableFrom(valueClass))
return new BigDecimal(((Number) value).toString());
if (java.lang.Character.class.isAssignableFrom(valueClass))
return BigDecimal.valueOf(((Character) value).charValue());
if (java.lang.String.class.isAssignableFrom(valueClass))
try {
return new BigDecimal(value.toString());
} catch (NumberFormatException ex) {
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(
value.toString()).append("' of type '").append(
valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return BigDecimal.valueOf(((Date) value).getTime());
} else if (java.sql.Date.class.isAssignableFrom(targetType)) {
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return new java.sql.Date(n.longValue());
}
if (java.lang.String.class.isAssignableFrom(valueClass)) {
DateFormat df = DateFormat.getDateInstance();
try {
java.util.Date d = df.parse(value.toString());
return new java.sql.Date(d.getTime());
} catch (ParseException ex) {
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(
value.toString()).append("' of type '").append(
valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return new java.sql.Date(((Date) value).getTime());
if (java.sql.Time.class.isAssignableFrom(valueClass))
return new java.sql.Date(((Time) value).getTime());
if (java.sql.Timestamp.class.isAssignableFrom(valueClass))
return new java.sql.Date(((Timestamp) value).getTime());
} else if (java.sql.Time.class.isAssignableFrom(targetType)) {
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return new Time(n.longValue());
}
if (java.lang.String.class.isAssignableFrom(valueClass)) {
DateFormat df = DateFormat.getTimeInstance();
try {
Date d = df.parse(value.toString());
return new Time(d.getTime());
} catch (ParseException ex) {
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(
value.toString()).append("' of type '").append(
valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return new Time(((Date) value).getTime());
if (java.sql.Date.class.isAssignableFrom(valueClass))
return new Time(((java.sql.Date) value).getTime());
if (java.sql.Timestamp.class.isAssignableFrom(valueClass))
return new Time(((Timestamp) value).getTime());
} else if (java.sql.Timestamp.class.isAssignableFrom(targetType)) {
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return new Timestamp(n.longValue());
}
if (java.lang.String.class.isAssignableFrom(valueClass)) {
DateFormat df = DateFormat.getDateTimeInstance();
try {
Date d = df.parse(value.toString());
return new Timestamp(d.getTime());
} catch (ParseException ex) {
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(
value.toString()).append("' of type '").append(
valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
}
if (java.util.Date.class.isAssignableFrom(valueClass))
return new Timestamp(((Date) value).getTime());
if (java.sql.Date.class.isAssignableFrom(valueClass))
return new Timestamp(((java.sql.Date) value).getTime());
if (java.sql.Time.class.isAssignableFrom(valueClass))
return new Timestamp(((Time) value).getTime());
} else if (java.util.Date.class.isAssignableFrom(targetType)) {
if (java.lang.Number.class.isAssignableFrom(valueClass)) {
BigDecimal n = new BigDecimal(((Number) value).toString());
return new Date(n.longValue());
}
if (java.lang.String.class.isAssignableFrom(valueClass)) {
DateFormat df = DateFormat.getDateTimeInstance();
try {
return df.parse(value.toString());
} catch (ParseException ex) {
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(
value.toString()).append("' of type '").append(
valueClass.toString()).append(
"' can not be casted to type '").append(
targetType.toString()).append("'.").toString());
}
}
}
}
throw new ClassCastException(
(new StringBuilder()).append("Value '").append(value.toString()).append(
"' of type '").append(valueClass.toString()).append(
"' can not be casted to type '").append(targetType.toString()).append(
"'.").toString());
}
/**
* @param <T>
* @param value
* @param targetType
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object transformEnum(Object value, Class targetType) {
if (!targetType.isEnum())
return null;
Enum<?> theEnum = null;
Object enumConsts[] = targetType.getEnumConstants();
List<String> constants = new ArrayList<String>();
for (Object cons : enumConsts) {
constants.add(cons.toString());
}
String valueStr = value.toString();
if (constants.contains(valueStr)) {
theEnum = Enum.valueOf(targetType, valueStr);
} else {
String valueStrLC = valueStr.toLowerCase();
for (String constant : constants) {
if (constant.toLowerCase().equals(valueStrLC)) {
theEnum = Enum.valueOf(targetType, constant);
break;
}
}
}
if (theEnum == null) {
if (log.isWarnEnabled())
log.warn("was not found the enum String" + value
+ "for targetType " + targetType.getName());
}
return targetType.cast(theEnum);
}
public static HashMap<Class<?>,Object> defaultTransformers;
static {
defaultTransformers = new HashMap<Class<?>,Object>();
Transformer boolTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
return Boolean.valueOf(input.toString());
}
};
defaultTransformers.put(Boolean.TYPE, boolTransform);
Transformer charTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new Character('\0');
else
return new Character(value.charAt(0));
}
};
defaultTransformers.put(Character.TYPE, charTransform);
defaultTransformers.put(Character.class, charTransform);
Transformer byteTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new Byte((byte) 0);
else
return Byte.valueOf(value);
}
};
defaultTransformers.put(Byte.TYPE, byteTransform);
defaultTransformers.put(Byte.class, byteTransform);
Transformer shortTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new Short((short) 0);
else
return Short.valueOf(value);
}
};
defaultTransformers.put(Short.TYPE, shortTransform);
defaultTransformers.put(Short.class, shortTransform);
Transformer intTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString().trim();
if ("".equals(value))
return new Integer(0);
else
return Integer.valueOf(value);
}
};
defaultTransformers.put(Integer.TYPE, intTransform);
defaultTransformers.put(Integer.class, intTransform);
Transformer longTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new Long(0L);
else
return Long.valueOf(value);
}
};
defaultTransformers.put(Long.TYPE, longTransform);
defaultTransformers.put(Long.class, longTransform);
Transformer floatTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new Float(0.0F);
else
return Float.valueOf(value);
}
};
defaultTransformers.put(Float.TYPE, floatTransform);
defaultTransformers.put(Float.class, floatTransform);
Transformer doubleTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new Double(0.0D);
else
return Double.valueOf(value);
}
};
defaultTransformers.put(Double.TYPE, doubleTransform);
defaultTransformers.put(Double.class, doubleTransform);
Transformer bigDecimalTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return new BigDecimal(0);
else
return new BigDecimal(value);
}
};
defaultTransformers.put(BigDecimal.class, bigDecimalTransform);
Transformer bigIntegerTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
String value = input.toString();
if ("".equals(value))
return BigInteger.ZERO;
else
return new BigInteger(value);
}
};
defaultTransformers.put(BigInteger.class, bigIntegerTransform);
Transformer javaSqlDateTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
if (input instanceof java.util.Date) {
Calendar c = Calendar.getInstance();
c.setTime((java.util.Date) input);
c.set(11, 0);
c.set(12, 0);
c.set(13, 0);
c.set(14, 0);
return new Date(c.getTime().getTime());
} else {
throw new Exception(
(new StringBuilder()).append("Can't covert type: ").append(
input.getClass().getName()).append(
" to java.sql.Date").toString());
}
}
};
defaultTransformers.put(Date.class, javaSqlDateTransform);
Transformer javaSqlTimeTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
if (input instanceof java.util.Date) {
Calendar c = Calendar.getInstance();
c.setTime((java.util.Date) input);
c.set(1970, 0, 1);
return new Time(c.getTime().getTime());
} else {
throw new Exception(
(new StringBuilder()).append("Can't covert type: ").append(
input.getClass().getName()).append(
" to java.sql.Time").toString());
}
}
};
defaultTransformers.put(Time.class, javaSqlTimeTransform);
Transformer javaSqlTimestampTransform = new Transformer() {
@Override
public Object transform(Object input) throws Exception {
if (input instanceof java.util.Date)
return new Timestamp(((java.util.Date) input).getTime());
else
throw new Exception((new StringBuilder()).append(
"Can't covert type: ").append(
input.getClass().getName()).append(
" to java.sql.Timestamp").toString());
}
};
defaultTransformers.put(Timestamp.class, javaSqlTimestampTransform);
}
}