private static Object realize1()

in dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java [351:630]


    private static Object realize1(
            Object pojo,
            Class<?> type,
            Type genericType,
            final Map<String, Type> mapParent,
            final Map<Object, Object> history) {
        if (pojo == null) {
            return null;
        }

        if (type != null && type.isEnum() && pojo.getClass() == String.class) {
            return Enum.valueOf((Class<Enum>) type, (String) pojo);
        }

        if (ReflectUtils.isPrimitives(pojo.getClass())
                && !(type != null
                        && type.isArray()
                        && type.getComponentType().isEnum()
                        && pojo.getClass() == String[].class)) {
            return CompatibleTypeUtils.compatibleTypeConvert(pojo, type);
        }

        Object o = history.get(pojo);

        if (o != null) {
            return o;
        }

        history.put(pojo, pojo);

        Map<String, Type> mapGeneric = new HashMap<>(8);
        mapGeneric.putAll(mapParent);
        TypeVariable<? extends Class<?>>[] typeParameters = type.getTypeParameters();
        if (genericType instanceof ParameterizedType && typeParameters.length > 0) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (int i = 0; i < typeParameters.length; i++) {
                if (!(actualTypeArguments[i] instanceof TypeVariable)) {
                    mapGeneric.put(typeParameters[i].getTypeName(), actualTypeArguments[i]);
                }
            }
        }

        if (pojo.getClass().isArray()) {
            if (Collection.class.isAssignableFrom(type)) {
                Class<?> ctype = pojo.getClass().getComponentType();
                int len = Array.getLength(pojo);
                Collection dest = createCollection(type, len);
                history.put(pojo, dest);
                for (int i = 0; i < len; i++) {
                    Object obj = Array.get(pojo, i);
                    Object value = realize1(obj, ctype, null, mapGeneric, history);
                    dest.add(value);
                }
                return dest;
            } else {
                Class<?> ctype = (type != null && type.isArray()
                        ? type.getComponentType()
                        : pojo.getClass().getComponentType());
                int len = Array.getLength(pojo);
                Object dest = Array.newInstance(ctype, len);
                history.put(pojo, dest);
                for (int i = 0; i < len; i++) {
                    Object obj = Array.get(pojo, i);
                    Object value = realize1(obj, ctype, null, mapGeneric, history);
                    Array.set(dest, i, value);
                }
                return dest;
            }
        }

        if (pojo instanceof Collection<?>) {
            if (type.isArray()) {
                Class<?> ctype = type.getComponentType();
                Collection<Object> src = (Collection<Object>) pojo;
                int len = src.size();
                Object dest = Array.newInstance(ctype, len);
                history.put(pojo, dest);
                int i = 0;
                for (Object obj : src) {
                    Object value = realize1(obj, ctype, null, mapGeneric, history);
                    Array.set(dest, i, value);
                    i++;
                }
                return dest;
            } else {
                Collection<Object> src = (Collection<Object>) pojo;
                int len = src.size();
                Collection<Object> dest = createCollection(type, len);
                history.put(pojo, dest);
                for (Object obj : src) {
                    Type keyType = getGenericClassByIndex(genericType, 0);
                    Class<?> keyClazz = obj == null ? null : obj.getClass();
                    if (keyType instanceof Class) {
                        keyClazz = (Class<?>) keyType;
                    }
                    Object value = realize1(obj, keyClazz, keyType, mapGeneric, history);
                    dest.add(value);
                }
                return dest;
            }
        }

        if (pojo instanceof Map<?, ?> && type != null) {
            Object className = ((Map<Object, Object>) pojo).get("class");
            if (className instanceof String) {
                if (!CLASS_NOT_FOUND_CACHE.containsKey(className)) {
                    try {
                        type = DefaultSerializeClassChecker.getInstance()
                                .loadClass(ClassUtils.getClassLoader(), (String) className);
                    } catch (ClassNotFoundException e) {
                        CLASS_NOT_FOUND_CACHE.put((String) className, NOT_FOUND_VALUE);
                    }
                }
            }

            // special logic for enum
            if (type.isEnum()) {
                Object name = ((Map<Object, Object>) pojo).get("name");
                if (name != null) {
                    if (!(name instanceof String)) {
                        throw new IllegalArgumentException("`name` filed should be string!");
                    } else {
                        return Enum.valueOf((Class<Enum>) type, (String) name);
                    }
                }
            }
            Map<Object, Object> map;
            // when return type is not the subclass of return type from the signature and not an interface
            if (!type.isInterface() && !type.isAssignableFrom(pojo.getClass())) {
                try {
                    map = (Map<Object, Object>) type.getDeclaredConstructor().newInstance();
                    Map<Object, Object> mapPojo = (Map<Object, Object>) pojo;
                    map.putAll(mapPojo);
                    if (GENERIC_WITH_CLZ) {
                        map.remove("class");
                    }
                } catch (Exception e) {
                    // ignore error
                    map = (Map<Object, Object>) pojo;
                }
            } else {
                map = (Map<Object, Object>) pojo;
            }

            if (Map.class.isAssignableFrom(type) || type == Object.class) {
                final Map<Object, Object> result;
                // fix issue#5939
                Type mapKeyType = getKeyTypeForMap(map.getClass());
                Type typeKeyType = getGenericClassByIndex(genericType, 0);
                boolean typeMismatch = mapKeyType instanceof Class
                        && typeKeyType instanceof Class
                        && !typeKeyType.getTypeName().equals(mapKeyType.getTypeName());
                if (typeMismatch) {
                    result = createMap(new HashMap(0));
                } else {
                    result = createMap(map);
                }

                history.put(pojo, result);
                for (Map.Entry<Object, Object> entry : map.entrySet()) {
                    Type keyType = getGenericClassByIndex(genericType, 0);
                    Type valueType = getGenericClassByIndex(genericType, 1);
                    Class<?> keyClazz;
                    if (keyType instanceof Class) {
                        keyClazz = (Class<?>) keyType;
                    } else if (keyType instanceof ParameterizedType) {
                        keyClazz = (Class<?>) ((ParameterizedType) keyType).getRawType();
                    } else {
                        keyClazz =
                                entry.getKey() == null ? null : entry.getKey().getClass();
                    }
                    Class<?> valueClazz;
                    if (valueType instanceof Class) {
                        valueClazz = (Class<?>) valueType;
                    } else if (valueType instanceof ParameterizedType) {
                        valueClazz = (Class<?>) ((ParameterizedType) valueType).getRawType();
                    } else {
                        valueClazz = entry.getValue() == null
                                ? null
                                : entry.getValue().getClass();
                    }

                    Object key = keyClazz == null
                            ? entry.getKey()
                            : realize1(entry.getKey(), keyClazz, keyType, mapGeneric, history);
                    Object value = valueClazz == null
                            ? entry.getValue()
                            : realize1(entry.getValue(), valueClazz, valueType, mapGeneric, history);
                    result.put(key, value);
                }
                return result;
            } else if (type.isInterface()) {
                Object dest = Proxy.newProxyInstance(
                        Thread.currentThread().getContextClassLoader(),
                        new Class<?>[] {type},
                        new PojoInvocationHandler(map));
                history.put(pojo, dest);
                return dest;
            } else {
                Object dest;
                if (Throwable.class.isAssignableFrom(type)) {
                    Object message = map.get("message");
                    if (message instanceof String) {
                        dest = newThrowableInstance(type, (String) message);
                    } else {
                        dest = newInstance(type);
                    }
                } else {
                    dest = newInstance(type);
                }

                history.put(pojo, dest);

                for (Map.Entry<Object, Object> entry : map.entrySet()) {
                    Object key = entry.getKey();
                    if (key instanceof String) {
                        String name = (String) key;
                        Object value = entry.getValue();
                        if (value != null) {
                            Method method = getSetterMethod(dest.getClass(), name, value.getClass());
                            Field field = getAndCacheField(dest.getClass(), name);
                            if (method != null) {
                                if (!method.isAccessible()) {
                                    method.setAccessible(true);
                                }
                                Type containType = Optional.ofNullable(field)
                                        .map(Field::getGenericType)
                                        .map(Type::getTypeName)
                                        .map(mapGeneric::get)
                                        .orElse(null);
                                if (containType != null) {
                                    // is generic
                                    if (containType instanceof ParameterizedType) {
                                        value = realize1(
                                                value,
                                                (Class<?>) ((ParameterizedType) containType).getRawType(),
                                                containType,
                                                mapGeneric,
                                                history);
                                    } else if (containType instanceof Class) {
                                        value = realize1(
                                                value, (Class<?>) containType, containType, mapGeneric, history);
                                    } else {
                                        Type ptype = method.getGenericParameterTypes()[0];
                                        value = realize1(
                                                value, method.getParameterTypes()[0], ptype, mapGeneric, history);
                                    }
                                } else {
                                    Type ptype = method.getGenericParameterTypes()[0];
                                    value = realize1(value, method.getParameterTypes()[0], ptype, mapGeneric, history);
                                }
                                try {
                                    method.invoke(dest, value);
                                } catch (Exception e) {
                                    String exceptionDescription = "Failed to set pojo "
                                            + dest.getClass().getSimpleName() + " property " + name + " value "
                                            + value.getClass() + ", cause: " + e.getMessage();
                                    logger.error(COMMON_REFLECTIVE_OPERATION_FAILED, "", "", exceptionDescription, e);
                                    throw new RuntimeException(exceptionDescription, e);
                                }
                            } else if (field != null) {
                                value = realize1(value, field.getType(), field.getGenericType(), mapGeneric, history);
                                try {
                                    field.set(dest, value);
                                } catch (IllegalAccessException e) {
                                    throw new RuntimeException(
                                            "Failed to set field " + name + " of pojo "
                                                    + dest.getClass().getName() + " : " + e.getMessage(),
                                            e);
                                }
                            }
                        }
                    }
                }
                return dest;
            }
        }
        return pojo;
    }