private Object doConvert()

in dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java [139:638]


    private <T> Object doConvert(Object source, Class<T> targetClass) throws Exception {
        if (source == null) {
            return nullDefault(targetClass);
        }

        if (targetClass.isInstance(source)) {
            return source;
        }

        if (targetClass == Optional.class) {
            return Optional.of(source);
        }

        Class sourceClass = source.getClass();
        if (sourceClass == Optional.class) {
            source = ((Optional<?>) source).orElse(null);
            if (source == null) {
                return nullDefault(targetClass);
            }

            if (targetClass.isInstance(source)) {
                return source;
            }
        }

        Object target = customConvert(source, targetClass);
        if (target != null) {
            return target;
        }

        if (source instanceof CharSequence) {
            String str = source.toString();

            if (targetClass == String.class) {
                return str;
            }

            if (str.isEmpty() || "null".equals(str) || "NULL".equals(str)) {
                return emptyDefault(targetClass);
            }

            switch (targetClass.getName()) {
                case "java.lang.Double":
                case "double":
                    return Double.valueOf(str);
                case "java.lang.Float":
                case "float":
                    return Float.valueOf(str);
                case "java.lang.Long":
                case "long":
                    return isHexNumber(str) ? Long.decode(str) : Long.valueOf(str);
                case "java.lang.Integer":
                case "int":
                    return isHexNumber(str) ? Integer.decode(str) : Integer.valueOf(str);
                case "java.lang.Short":
                case "short":
                    return isHexNumber(str) ? Short.decode(str) : Short.valueOf(str);
                case "java.lang.Character":
                case "char":
                    if (str.length() == 1) {
                        return str.charAt(0);
                    }
                    throw new RestParameterException("Can not convert String(" + str + ") to char, must only 1 char");
                case "java.lang.Byte":
                case "byte":
                    return isHexNumber(str) ? Byte.decode(str) : Byte.valueOf(str);
                case "java.lang.Boolean":
                    return toBoolean(str);
                case "boolean":
                    return toBoolean(str) == Boolean.TRUE;
                case "java.math.BigInteger":
                    return new BigInteger(str);
                case "java.math.BigDecimal":
                    return new BigDecimal(str);
                case "java.lang.Number":
                    return str.indexOf('.') == -1 ? doConvert(str, Long.class) : doConvert(str, Double.class);
                case "java.util.Date":
                    return DateUtils.parse(str);
                case "java.util.Calendar":
                    Calendar cal = Calendar.getInstance();
                    cal.setTimeInMillis(DateUtils.parse(str).getTime());
                    return cal;
                case "java.sql.Timestamp":
                    return new Timestamp(DateUtils.parse(str).getTime());
                case "java.time.Instant":
                    return DateUtils.parse(str).toInstant();
                case "java.time.ZonedDateTime":
                    return toZonedDateTime(str);
                case "java.time.LocalDate":
                    return toZonedDateTime(str).toLocalDate();
                case "java.time.LocalTime":
                    return toZonedDateTime(str).toLocalTime();
                case "java.time.LocalDateTime":
                    return toZonedDateTime(str).toLocalDateTime();
                case "java.time.ZoneId":
                    return TimeZone.getTimeZone(str).toZoneId();
                case "java.util.TimeZone":
                    return TimeZone.getTimeZone(str);
                case "java.io.File":
                    return new File(str);
                case "java.nio.file.Path":
                    return Paths.get(str);
                case "java.nio.charset.Charset":
                    return Charset.forName(str);
                case "java.net.InetAddress":
                    return InetAddress.getByName(str);
                case "java.net.URI":
                    return new URI(str);
                case "java.net.URL":
                    return new URL(str);
                case "java.util.UUID":
                    return UUID.fromString(str);
                case "java.util.Locale":
                    String[] parts = StringUtils.tokenize(str, '-', '_');
                    switch (parts.length) {
                        case 2:
                            return new Locale(parts[0], parts[1]);
                        case 3:
                            return new Locale(parts[0], parts[1], parts[2]);
                        default:
                            return new Locale(parts[0]);
                    }
                case "java.util.Currency":
                    return Currency.getInstance(str);
                case "java.util.regex.Pattern":
                    return Pattern.compile(str);
                case "java.lang.Class":
                    return ClassUtils.loadClass(str);
                case "[B":
                    return str.getBytes(UTF_8);
                case "[C":
                    return str.toCharArray();
                case "java.util.OptionalInt":
                    return OptionalInt.of(isHexNumber(str) ? Integer.decode(str) : Integer.parseInt(str));
                case "java.util.OptionalLong":
                    return OptionalLong.of(isHexNumber(str) ? Long.decode(str) : Long.parseLong(str));
                case "java.util.OptionalDouble":
                    return OptionalDouble.of(Double.parseDouble(str));
                case "java.util.Properties":
                    Properties properties = new Properties();
                    properties.load(new StringReader(str));
                    return properties;
                default:
            }

            if (targetClass.isEnum()) {
                try {
                    return Enum.valueOf((Class<Enum>) targetClass, str);
                } catch (Exception ignored) {
                }
            }

            target = jsonToObject(str, targetClass);
            if (target != null) {
                return target;
            }

            if (targetClass.isArray()) {
                List<String> list = tokenizeToList(str);
                int n = list.size();
                Class itemType = targetClass.getComponentType();
                if (itemType == String.class) {
                    return list.toArray(StringUtils.EMPTY_STRING_ARRAY);
                }
                Object arr = Array.newInstance(itemType, n);
                for (int i = 0; i < n; i++) {
                    Array.set(arr, i, doConvert(list.get(i), itemType));
                }
                return arr;
            } else if (Collection.class.isAssignableFrom(targetClass)) {
                target = convertCollection(tokenizeToList(str), targetClass);
                if (target != null) {
                    return target;
                }
            } else if (Map.class.isAssignableFrom(targetClass)) {
                target = convertMap(tokenizeToMap(str), targetClass);
                if (target != null) {
                    return target;
                }
            }
        } else if (source instanceof Number) {
            Number num = (Number) source;

            switch (targetClass.getName()) {
                case "java.lang.String":
                    return source.toString();
                case "java.lang.Double":
                case "double":
                    return num.doubleValue();
                case "java.lang.Float":
                case "float":
                    return num.floatValue();
                case "java.lang.Long":
                case "long":
                    return num.longValue();
                case "java.lang.Integer":
                case "int":
                    return num.intValue();
                case "java.lang.Short":
                case "short":
                    return num.shortValue();
                case "java.lang.Character":
                case "char":
                    return (char) num.intValue();
                case "java.lang.Byte":
                case "byte":
                    return num.byteValue();
                case "java.lang.Boolean":
                case "boolean":
                    return toBoolean(num);
                case "java.math.BigInteger":
                    return BigInteger.valueOf(num.longValue());
                case "java.math.BigDecimal":
                    return BigDecimal.valueOf(num.doubleValue());
                case "java.util.Date":
                    return new Date(num.longValue());
                case "java.util.Calendar":
                    Calendar cal = Calendar.getInstance();
                    cal.setTimeInMillis(num.longValue());
                    return cal;
                case "java.sql.Timestamp":
                    return new Timestamp(num.longValue());
                case "java.time.Instant":
                    return Instant.ofEpochMilli(num.longValue());
                case "java.time.ZonedDateTime":
                    return toZonedDateTime(num);
                case "java.time.LocalDate":
                    return toZonedDateTime(num).toLocalDate();
                case "java.time.LocalTime":
                    return toZonedDateTime(num).toLocalTime();
                case "java.time.LocalDateTime":
                    return toZonedDateTime(num).toLocalDateTime();
                case "java.util.TimeZone":
                    return toTimeZone(num.intValue());
                case "[B":
                    return toBytes(num);
                case "[C":
                    return new char[] {(char) num.intValue()};
                case "java.util.OptionalInt":
                    return OptionalInt.of(num.intValue());
                case "java.util.OptionalLong":
                    return OptionalLong.of(num.longValue());
                case "java.util.OptionalDouble":
                    return OptionalDouble.of(num.doubleValue());
                default:
            }

            if (targetClass.isEnum()) {
                for (T e : targetClass.getEnumConstants()) {
                    if (((Enum) e).ordinal() == num.intValue()) {
                        return e;
                    }
                }
            }
        } else if (source instanceof Date) {
            Date date = (Date) source;
            switch (targetClass.getName()) {
                case "java.lang.String":
                    return DateUtils.format(date);
                case "java.lang.Long":
                case "long":
                    return date.getTime();
                case "java.lang.Integer":
                case "int":
                    return (int) (date.getTime() / 1000);
                case "java.util.Calendar":
                    Calendar cal = Calendar.getInstance();
                    cal.setTimeInMillis(date.getTime());
                    return cal;
                case "java.time.Instant":
                    return date.toInstant();
                case "java.time.ZonedDateTime":
                    return toZonedDateTime(date.getTime());
                case "java.time.LocalDate":
                    return toZonedDateTime(date.getTime()).toLocalDate();
                case "java.time.LocalTime":
                    return toZonedDateTime(date.getTime()).toLocalTime();
                case "java.time.LocalDateTime":
                    return toZonedDateTime(date.getTime()).toLocalDateTime();
                default:
            }
        } else if (source instanceof TemporalAccessor) {
            return doConvert(DateUtils.toDate((TemporalAccessor) source), targetClass);
        } else if (source instanceof Enum) {
            Enum en = (Enum) source;
            if (targetClass == String.class) {
                return en.toString();
            }
            if (targetClass == int.class || targetClass == Integer.class) {
                return en.ordinal();
            }
            if (Number.class.isAssignableFrom(targetClass)) {
                return doConvert(en.ordinal(), targetClass);
            }
            if (targetClass.isEnum()) {
                return Enum.valueOf((Class<Enum>) targetClass, en.name());
            }
        } else if (source instanceof byte[]) {
            byte[] bytes = (byte[]) source;

            if (bytes.length == 0) {
                return emptyDefault(targetClass);
            }

            switch (targetClass.getName()) {
                case "java.lang.String":
                    return new String(bytes, UTF_8);
                case "java.lang.Double":
                case "double":
                    return ByteBuffer.wrap(bytes).getDouble();
                case "java.lang.Float":
                case "float":
                    return ByteBuffer.wrap(bytes).getFloat();
                case "java.lang.Long":
                case "long":
                    return ByteBuffer.wrap(bytes).getLong();
                case "java.lang.Integer":
                case "int":
                    return ByteBuffer.wrap(bytes).getInt();
                case "java.lang.Short":
                case "short":
                    return ByteBuffer.wrap(bytes).getShort();
                case "java.lang.Character":
                case "char":
                    return ByteBuffer.wrap(bytes).getChar();
                case "java.lang.Byte":
                case "byte":
                    return bytes[0];
                case "java.lang.Boolean":
                case "boolean":
                    return bytes[0] == (byte) 0 ? Boolean.FALSE : Boolean.TRUE;
                case "java.math.BigInteger":
                    return new BigInteger(bytes);
                case "java.util.Properties":
                    Properties properties = new Properties();
                    properties.load(new ByteArrayInputStream(bytes));
                    return properties;
                default:
            }

            target = jsonToObject(new String(bytes, StandardCharsets.ISO_8859_1), targetClass);
            if (target != null) {
                return target;
            }
        }

        if (targetClass.isArray()) {
            if (targetClass == byte[].class) {
                if (source instanceof InputStream) {
                    try (InputStream is = (InputStream) source) {
                        return StreamUtils.readBytes(is);
                    }
                }
                if (source instanceof FileUpload) {
                    try (InputStream is = ((FileUpload) source).inputStream()) {
                        return StreamUtils.readBytes(is);
                    }
                }
                if (source instanceof Character) {
                    char c = (Character) source;
                    return new byte[] {(byte) (c >> 8), (byte) c};
                }
                if (source instanceof Boolean) {
                    boolean b = (Boolean) source;
                    return new byte[] {b ? (byte) 1 : (byte) 0};
                }
            }

            Class itemType = targetClass.getComponentType();

            if (source instanceof Collection) {
                Collection c = (Collection) source;
                int i = 0;
                Object arr = Array.newInstance(itemType, c.size());
                for (Object item : c) {
                    Array.set(arr, i++, item == null ? null : doConvert(item, itemType));
                }
                return arr;
            }

            if (source instanceof Iterable) {
                List list = new ArrayList();
                for (Object item : (Iterable) source) {
                    list.add(item == null ? null : doConvert(item, itemType));
                }
                return list.toArray((Object[]) Array.newInstance(itemType, 0));
            }

            if (sourceClass.isArray()) {
                int len = Array.getLength(source);
                Object arr = Array.newInstance(itemType, len);
                for (int i = 0; i < len; i++) {
                    Object item = Array.get(source, i);
                    Array.set(arr, i, item == null ? null : doConvert(item, itemType));
                }
                return arr;
            }

            Object arr = Array.newInstance(itemType, 1);
            Array.set(arr, 0, doConvert(source, itemType));
            return arr;
        }

        if (Collection.class.isAssignableFrom(targetClass)) {
            target = convertCollection(toCollection(source), targetClass);
            if (target != null) {
                return target;
            }
        }

        if (Map.class.isAssignableFrom(targetClass) && source instanceof Map) {
            target = convertMap((Map) source, targetClass);
            if (target != null) {
                return target;
            }
        }

        if (sourceClass.isArray()) {
            if (Array.getLength(source) == 0) {
                return nullDefault(targetClass);
            }
            return doConvert(Array.get(source, 0), targetClass);
        }

        if (source instanceof List) {
            List list = (List) source;
            if (list.isEmpty()) {
                return nullDefault(targetClass);
            }
            return doConvert(list.get(0), targetClass);
        }

        if (source instanceof Iterable) {
            Iterator it = ((Iterable) source).iterator();
            if (!it.hasNext()) {
                return nullDefault(targetClass);
            }
            return doConvert(it.next(), targetClass);
        }

        if (targetClass == String.class) {
            if (sourceClass == HttpCookie.class) {
                return ((HttpCookie) source).value();
            }
            if (source instanceof InputStream) {
                try (InputStream is = (InputStream) source) {
                    return StreamUtils.toString(is);
                }
            }
            if (source instanceof FileUpload) {
                FileUpload fu = (FileUpload) source;
                try (InputStream is = fu.inputStream()) {
                    String contentType = fu.contentType();
                    if (contentType != null) {
                        int index = contentType.lastIndexOf(HttpUtils.CHARSET_PREFIX);
                        if (index > 0) {
                            return StreamUtils.toString(
                                    is,
                                    Charset.forName(
                                            contentType.substring(index + 8).trim()));
                        }
                    }
                    return StreamUtils.toString(is);
                }
            }
            return source.toString();
        }

        if (!Modifier.isAbstract(targetClass.getModifiers())) {
            try {
                for (Constructor ct : targetClass.getConstructors()) {
                    if (ct.getParameterCount() == 1) {
                        if (ct.getParameterTypes()[0].isAssignableFrom(sourceClass)) {
                            return ct.newInstance(source);
                        }
                    }
                }
            } catch (Throwable ignored) {
            }
        }

        if (sourceClass == String.class) {
            try {
                Method valueOf = targetClass.getMethod("valueOf", String.class);
                //noinspection JavaReflectionInvocation
                return valueOf.invoke(null, source);
            } catch (Throwable ignored) {
            }
            return null;
        }

        try {
            return httpJsonUtils.convertObject(source, targetClass);
        } catch (Throwable t) {
            String msg = "JSON convert value '{}' from type [{}] to type [{}] failed";
            LOGGER.debug(msg, source, sourceClass, targetClass, t);
        }

        return null;
    }