@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);
            }
            if (type.isEnum()) {
                return Enum.valueOf((Class<Enum>) type, string);
            }
            if (type == BigInteger.class) {
                return new BigInteger(string);
            }
            if (type == BigDecimal.class) {
                return new BigDecimal(string);
            }
            if (type == Short.class || type == short.class) {
                return new Short(string);
            }
            if (type == Integer.class || type == int.class) {
                return new Integer(string);
            }
            if (type == Long.class || type == long.class) {
                return new Long(string);
            }
            if (type == Double.class || type == double.class) {
                return new Double(string);
            }
            if (type == Float.class || type == float.class) {
                return new Float(string);
            }
            if (type == Byte.class || type == byte.class) {
                return new Byte(string);
            }
            if (type == Boolean.class || type == boolean.class) {
                return Boolean.valueOf(string);
            }
            if (type == Date.class
                    || type == java.sql.Date.class
                    || type == java.sql.Timestamp.class
                    || type == java.sql.Time.class) {
                try {
                    Date date = new SimpleDateFormat(DATE_FORMAT).parse(string);
                    if (type == java.sql.Date.class) {
                        return new java.sql.Date(date.getTime());
                    }
                    if (type == java.sql.Timestamp.class) {
                        return new java.sql.Timestamp(date.getTime());
                    }
                    if (type == java.sql.Time.class) {
                        return new java.sql.Time(date.getTime());
                    }
                    return date;
                } catch (ParseException e) {
                    throw new IllegalStateException(
                            "Failed to parse date " + value + " by format " + DATE_FORMAT + ", cause: "
                                    + e.getMessage(),
                            e);
                }
            }
            if (type == java.time.LocalDateTime.class) {
                if (StringUtils.isEmpty(string)) {
                    return null;
                }
                return LocalDateTime.parse(string);
            }
            if (type == java.time.LocalDate.class) {
                if (StringUtils.isEmpty(string)) {
                    return null;
                }
                return LocalDate.parse(string);
            }
            if (type == java.time.LocalTime.class) {
                if (StringUtils.isEmpty(string)) {
                    return null;
                }

                if (string.length() >= ISO_LOCAL_DATE_TIME_MIN_LEN) {
                    return LocalDateTime.parse(string).toLocalTime();
                } else {
                    return LocalTime.parse(string);
                }
            }
            if (type == Class.class) {
                try {
                    return ReflectUtils.name2class(string);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
            if (char[].class.equals(type)) {
                // Process string to char array for generic invoke
                // See
                // - https://github.com/apache/dubbo/issues/2003
                int len = string.length();
                char[] chars = new char[len];
                string.getChars(0, len, chars, 0);
                return chars;
            }
        }
        if (value instanceof Number) {
            Number number = (Number) value;
            if (type == byte.class || type == Byte.class) {
                return number.byteValue();
            }
            if (type == short.class || type == Short.class) {
                return number.shortValue();
            }
            if (type == int.class || type == Integer.class) {
                return number.intValue();
            }
            if (type == long.class || type == Long.class) {
                return number.longValue();
            }
            if (type == float.class || type == Float.class) {
                return number.floatValue();
            }
            if (type == double.class || type == Double.class) {
                return number.doubleValue();
            }
            if (type == BigInteger.class) {
                return BigInteger.valueOf(number.longValue());
            }
            if (type == BigDecimal.class) {
                return new BigDecimal(number.toString());
            }
            if (type == Date.class) {
                return new Date(number.longValue());
            }
            if (type == boolean.class || type == Boolean.class) {
                return 0 != number.intValue();
            }
        }
        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;
            }
            if (!type.isInterface()) {
                try {
                    Collection result =
                            (Collection) type.getDeclaredConstructor().newInstance();
                    result.addAll(collection);
                    return result;
                } catch (Throwable ignored) {
                }
            }
            if (type == List.class) {
                return new ArrayList<Object>(collection);
            }
            if (type == Set.class) {
                return new HashSet<Object>(collection);
            }
        }
        if (value.getClass().isArray() && Collection.class.isAssignableFrom(type)) {
            int length = Array.getLength(value);
            Collection collection;
            if (!type.isInterface()) {
                try {
                    collection = (Collection) type.getDeclaredConstructor().newInstance();
                } catch (Exception e) {
                    collection = new ArrayList<Object>(length);
                }
            } else if (type == Set.class) {
                collection = new HashSet<Object>(Math.max((int) (length / .75f) + 1, 16));
            } else {
                collection = new ArrayList<Object>(length);
            }
            for (int i = 0; i < length; i++) {
                collection.add(Array.get(value, i));
            }
            return collection;
        }
        return value;
    }
@SuppressWarnings("unchecked")
    @Test
    void testCompatibleTypeConvert() throws Exception {
        Object result;

        {
            Object input = new Object();
            result = CompatibleTypeUtils.compatibleTypeConvert(input, Date.class);
            assertSame(input, result);

            result = CompatibleTypeUtils.compatibleTypeConvert(input, null);
            assertSame(input, result);

            result = CompatibleTypeUtils.compatibleTypeConvert(null, Date.class);
            assertNull(result);
        }

        {
            result = CompatibleTypeUtils.compatibleTypeConvert("a", char.class);
            assertEquals(Character.valueOf('a'), (Character) result);

            result = CompatibleTypeUtils.compatibleTypeConvert("A", MyEnum.class);
            assertEquals(MyEnum.A, (MyEnum) result);

            result = CompatibleTypeUtils.compatibleTypeConvert("3", BigInteger.class);
            assertEquals(new BigInteger("3"), (BigInteger) result);

            result = CompatibleTypeUtils.compatibleTypeConvert("3", BigDecimal.class);
            assertEquals(new BigDecimal("3"), (BigDecimal) result);

            result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11 12:24:12", Date.class);
            assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-12-11 12:24:12"), (Date) result);

            result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11 12:24:12", java.sql.Date.class);
            assertEquals(new SimpleDateFormat("yyyy-MM-dd").format((java.sql.Date) result), "2011-12-11");

            result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11 12:24:12", java.sql.Time.class);
            assertEquals(new SimpleDateFormat("HH:mm:ss").format((java.sql.Time) result), "12:24:12");

            result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11 12:24:12", java.sql.Timestamp.class);
            assertEquals(
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((java.sql.Timestamp) result),
                    "2011-12-11 12:24:12");

            result =
                    CompatibleTypeUtils.compatibleTypeConvert("2011-12-11T12:24:12.047", java.time.LocalDateTime.class);
            assertEquals(
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format((java.time.LocalDateTime) result),
                    "2011-12-11 12:24:12");

            result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11T12:24:12.047", java.time.LocalTime.class);
            assertEquals(DateTimeFormatter.ofPattern("HH:mm:ss").format((java.time.LocalTime) result), "12:24:12");

            result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11", java.time.LocalDate.class);
            assertEquals(DateTimeFormatter.ofPattern("yyyy-MM-dd").format((java.time.LocalDate) result), "2011-12-11");

            result = CompatibleTypeUtils.compatibleTypeConvert("ab", char[].class);
            assertEquals(2, ((char[]) result).length);
            assertEquals('a', ((char[]) result)[0]);
            assertEquals('b', ((char[]) result)[1]);

            result = CompatibleTypeUtils.compatibleTypeConvert("", char[].class);
            assertEquals(0, ((char[]) result).length);

            result = CompatibleTypeUtils.compatibleTypeConvert(null, char[].class);
            assertNull(result);
        }

        {
            result = CompatibleTypeUtils.compatibleTypeConvert(3, byte.class);
            assertEquals(Byte.valueOf((byte) 3), (Byte) result);

            result = CompatibleTypeUtils.compatibleTypeConvert((byte) 3, int.class);
            assertEquals(Integer.valueOf(3), (Integer) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3, short.class);
            assertEquals(Short.valueOf((short) 3), (Short) result);

            result = CompatibleTypeUtils.compatibleTypeConvert((short) 3, int.class);
            assertEquals(Integer.valueOf(3), (Integer) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3, int.class);
            assertEquals(Integer.valueOf(3), (Integer) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3, long.class);
            assertEquals(Long.valueOf(3), (Long) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3L, int.class);
            assertEquals(Integer.valueOf(3), (Integer) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3L, BigInteger.class);
            assertEquals(BigInteger.valueOf(3L), (BigInteger) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(BigInteger.valueOf(3L), int.class);
            assertEquals(Integer.valueOf(3), (Integer) result);
        }

        {
            result = CompatibleTypeUtils.compatibleTypeConvert(3D, float.class);
            assertEquals(Float.valueOf(3), (Float) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3F, double.class);
            assertEquals(Double.valueOf(3), (Double) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3D, double.class);
            assertEquals(Double.valueOf(3), (Double) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(3D, BigDecimal.class);
            assertEquals(BigDecimal.valueOf(3D), (BigDecimal) result);

            result = CompatibleTypeUtils.compatibleTypeConvert(BigDecimal.valueOf(3D), double.class);
            assertEquals(Double.valueOf(3), (Double) result);
        }

        {
            List<String> list = new ArrayList<String>();
            list.add("a");
            list.add("b");

            Set<String> set = new HashSet<String>();
            set.add("a");
            set.add("b");

            String[] array = new String[] {"a", "b"};

            result = CompatibleTypeUtils.compatibleTypeConvert(array, List.class);
            assertEquals(ArrayList.class, result.getClass());
            assertEquals(2, ((List<String>) result).size());
            assertTrue(((List<String>) result).contains("a"));
            assertTrue(((List<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(set, List.class);
            assertEquals(ArrayList.class, result.getClass());
            assertEquals(2, ((List<String>) result).size());
            assertTrue(((List<String>) result).contains("a"));
            assertTrue(((List<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(array, CopyOnWriteArrayList.class);
            assertEquals(CopyOnWriteArrayList.class, result.getClass());
            assertEquals(2, ((List<String>) result).size());
            assertTrue(((List<String>) result).contains("a"));
            assertTrue(((List<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(set, CopyOnWriteArrayList.class);
            assertEquals(CopyOnWriteArrayList.class, result.getClass());
            assertEquals(2, ((List<String>) result).size());
            assertTrue(((List<String>) result).contains("a"));
            assertTrue(((List<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(set, String[].class);
            assertEquals(String[].class, result.getClass());
            assertEquals(2, ((String[]) result).length);
            assertTrue(((String[]) result)[0].equals("a") || ((String[]) result)[0].equals("b"));
            assertTrue(((String[]) result)[1].equals("a") || ((String[]) result)[1].equals("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(array, Set.class);
            assertEquals(HashSet.class, result.getClass());
            assertEquals(2, ((Set<String>) result).size());
            assertTrue(((Set<String>) result).contains("a"));
            assertTrue(((Set<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(list, Set.class);
            assertEquals(HashSet.class, result.getClass());
            assertEquals(2, ((Set<String>) result).size());
            assertTrue(((Set<String>) result).contains("a"));
            assertTrue(((Set<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(array, ConcurrentHashSet.class);
            assertEquals(ConcurrentHashSet.class, result.getClass());
            assertEquals(2, ((Set<String>) result).size());
            assertTrue(((Set<String>) result).contains("a"));
            assertTrue(((Set<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(list, ConcurrentHashSet.class);
            assertEquals(ConcurrentHashSet.class, result.getClass());
            assertEquals(2, ((Set<String>) result).size());
            assertTrue(((Set<String>) result).contains("a"));
            assertTrue(((Set<String>) result).contains("b"));

            result = CompatibleTypeUtils.compatibleTypeConvert(list, String[].class);
            assertEquals(String[].class, result.getClass());
            assertEquals(2, ((String[]) result).length);
            assertTrue(((String[]) result)[0].equals("a"));
            assertTrue(((String[]) result)[1].equals("b"));
        }
    }