/* | |
* 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 com.alibaba.dubbo.common.utils; | |
import java.lang.reflect.Array; | |
import java.math.BigDecimal; | |
import java.math.BigInteger; | |
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Date; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
public class CompatibleTypeUtils { | |
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; | |
private CompatibleTypeUtils() { | |
} | |
/** | |
* Compatible type convert. Null value is allowed to pass in. If no conversion is needed, then the original value | |
* will be returned. | |
* <p> | |
* Supported compatible type conversions include (primary types and corresponding wrappers are not listed): | |
* <ul> | |
* <li> String -> char, enum, Date | |
* <li> byte, short, int, long -> byte, short, int, long | |
* <li> float, double -> float, double | |
* </ul> | |
*/ | |
@SuppressWarnings({"unchecked", "rawtypes"}) | |
public static Object compatibleTypeConvert(Object value, Class<?> type) { | |
if (value == null || type == null || type.isAssignableFrom(value.getClass())) { | |
return value; | |
} | |
if (value instanceof String) { | |
String string = (String) value; | |
if (char.class.equals(type) || Character.class.equals(type)) { | |
if (string.length() != 1) { | |
throw new IllegalArgumentException(String.format("CAN NOT convert String(%s) to char!" + | |
" when convert String to char, the String MUST only 1 char.", string)); | |
} | |
return string.charAt(0); | |
} else if (type.isEnum()) { | |
return Enum.valueOf((Class<Enum>) type, string); | |
} else if (type == BigInteger.class) { | |
return new BigInteger(string); | |
} else if (type == BigDecimal.class) { | |
return new BigDecimal(string); | |
} else if (type == Short.class || type == short.class) { | |
return new Short(string); | |
} else if (type == Integer.class || type == int.class) { | |
return new Integer(string); | |
} else if (type == Long.class || type == long.class) { | |
return new Long(string); | |
} else if (type == Double.class || type == double.class) { | |
return new Double(string); | |
} else if (type == Float.class || type == float.class) { | |
return new Float(string); | |
} else if (type == Byte.class || type == byte.class) { | |
return new Byte(string); | |
} else if (type == Boolean.class || type == boolean.class) { | |
return new Boolean(string); | |
} else if (type == Date.class) { | |
try { | |
return new SimpleDateFormat(DATE_FORMAT).parse((String) value); | |
} catch (ParseException e) { | |
throw new IllegalStateException("Failed to parse date " + value + " by format " + DATE_FORMAT + ", cause: " + e.getMessage(), e); | |
} | |
} else if (type == Class.class) { | |
try { | |
return ReflectUtils.name2class((String) value); | |
} catch (ClassNotFoundException e) { | |
throw new RuntimeException(e.getMessage(), e); | |
} | |
} | |
} else if (value instanceof Number) { | |
Number number = (Number) value; | |
if (type == byte.class || type == Byte.class) { | |
return number.byteValue(); | |
} else if (type == short.class || type == Short.class) { | |
return number.shortValue(); | |
} else if (type == int.class || type == Integer.class) { | |
return number.intValue(); | |
} else if (type == long.class || type == Long.class) { | |
return number.longValue(); | |
} else if (type == float.class || type == Float.class) { | |
return number.floatValue(); | |
} else if (type == double.class || type == Double.class) { | |
return number.doubleValue(); | |
} else if (type == BigInteger.class) { | |
return BigInteger.valueOf(number.longValue()); | |
} else if (type == BigDecimal.class) { | |
return BigDecimal.valueOf(number.doubleValue()); | |
} else if (type == Date.class) { | |
return new Date(number.longValue()); | |
} | |
} else if (value instanceof Collection) { | |
Collection collection = (Collection) value; | |
if (type.isArray()) { | |
int length = collection.size(); | |
Object array = Array.newInstance(type.getComponentType(), length); | |
int i = 0; | |
for (Object item : collection) { | |
Array.set(array, i++, item); | |
} | |
return array; | |
} else if (!type.isInterface()) { | |
try { | |
Collection result = (Collection) type.newInstance(); | |
result.addAll(collection); | |
return result; | |
} catch (Throwable e) { | |
} | |
} else if (type == List.class) { | |
return new ArrayList<Object>(collection); | |
} else if (type == Set.class) { | |
return new HashSet<Object>(collection); | |
} | |
} else if (value.getClass().isArray() && Collection.class.isAssignableFrom(type)) { | |
Collection collection; | |
if (!type.isInterface()) { | |
try { | |
collection = (Collection) type.newInstance(); | |
} catch (Throwable e) { | |
collection = new ArrayList<Object>(); | |
} | |
} else if (type == Set.class) { | |
collection = new HashSet<Object>(); | |
} else { | |
collection = new ArrayList<Object>(); | |
} | |
int length = Array.getLength(value); | |
for (int i = 0; i < length; i++) { | |
collection.add(Array.get(value, i)); | |
} | |
return collection; | |
} | |
return value; | |
} | |
} |