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;
}