dubbo JavaBeanSerializeUtil 源码
dubbo JavaBeanSerializeUtil 代码
文件路径:/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
/*
* 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 org.apache.dubbo.common.beanutil;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.LogHelper;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.SerializeClassChecker;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
public final class JavaBeanSerializeUtil {
private static final Logger logger = LoggerFactory.getLogger(JavaBeanSerializeUtil.class);
private static final Map<String, Class<?>> TYPES = new HashMap<String, Class<?>>();
private static final String ARRAY_PREFIX = "[";
private static final String REFERENCE_TYPE_PREFIX = "L";
private static final String REFERENCE_TYPE_SUFFIX = ";";
static {
TYPES.put(boolean.class.getName(), boolean.class);
TYPES.put(byte.class.getName(), byte.class);
TYPES.put(short.class.getName(), short.class);
TYPES.put(int.class.getName(), int.class);
TYPES.put(long.class.getName(), long.class);
TYPES.put(float.class.getName(), float.class);
TYPES.put(double.class.getName(), double.class);
TYPES.put(void.class.getName(), void.class);
TYPES.put("Z", boolean.class);
TYPES.put("B", byte.class);
TYPES.put("C", char.class);
TYPES.put("D", double.class);
TYPES.put("F", float.class);
TYPES.put("I", int.class);
TYPES.put("J", long.class);
TYPES.put("S", short.class);
}
private JavaBeanSerializeUtil() {
}
public static JavaBeanDescriptor serialize(Object obj) {
return serialize(obj, JavaBeanAccessor.FIELD);
}
public static JavaBeanDescriptor serialize(Object obj, JavaBeanAccessor accessor) {
if (obj == null) {
return null;
}
if (obj instanceof JavaBeanDescriptor) {
return (JavaBeanDescriptor) obj;
}
IdentityHashMap<Object, JavaBeanDescriptor> cache = new IdentityHashMap<Object, JavaBeanDescriptor>();
return createDescriptorIfAbsent(obj, accessor, cache);
}
private static JavaBeanDescriptor createDescriptorForSerialize(Class<?> cl) {
if (cl.isEnum()) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_ENUM);
}
if (cl.isArray()) {
return new JavaBeanDescriptor(cl.getComponentType().getName(), JavaBeanDescriptor.TYPE_ARRAY);
}
if (ReflectUtils.isPrimitive(cl)) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);
}
if (Class.class.equals(cl)) {
return new JavaBeanDescriptor(Class.class.getName(), JavaBeanDescriptor.TYPE_CLASS);
}
if (Collection.class.isAssignableFrom(cl)) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_COLLECTION);
}
if (Map.class.isAssignableFrom(cl)) {
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_MAP);
}
return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_BEAN);
}
private static JavaBeanDescriptor createDescriptorIfAbsent(Object obj, JavaBeanAccessor accessor,
IdentityHashMap<Object, JavaBeanDescriptor> cache) {
if (cache.containsKey(obj)) {
return cache.get(obj);
}
if (obj instanceof JavaBeanDescriptor) {
return (JavaBeanDescriptor) obj;
}
JavaBeanDescriptor result = createDescriptorForSerialize(obj.getClass());
cache.put(obj, result);
serializeInternal(result, obj, accessor, cache);
return result;
}
private static void serializeInternal(JavaBeanDescriptor descriptor, Object obj, JavaBeanAccessor accessor,
IdentityHashMap<Object, JavaBeanDescriptor> cache) {
if (obj == null || descriptor == null) {
return;
}
if (obj.getClass().isEnum()) {
descriptor.setEnumNameProperty(((Enum<?>) obj).name());
} else if (ReflectUtils.isPrimitive(obj.getClass())) {
descriptor.setPrimitiveProperty(obj);
} else if (Class.class.equals(obj.getClass())) {
descriptor.setClassNameProperty(((Class<?>) obj).getName());
} else if (obj.getClass().isArray()) {
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
Object item = Array.get(obj, i);
if (item == null) {
descriptor.setProperty(i, null);
} else {
JavaBeanDescriptor itemDescriptor = createDescriptorIfAbsent(item, accessor, cache);
descriptor.setProperty(i, itemDescriptor);
}
}
} else if (obj instanceof Collection) {
Collection collection = (Collection) obj;
int index = 0;
for (Object item : collection) {
if (item == null) {
descriptor.setProperty(index++, null);
} else {
JavaBeanDescriptor itemDescriptor = createDescriptorIfAbsent(item, accessor, cache);
descriptor.setProperty(index++, itemDescriptor);
}
}
} else if (obj instanceof Map) {
Map map = (Map) obj;
map.forEach((key, value) -> {
Object keyDescriptor = key == null ? null : createDescriptorIfAbsent(key, accessor, cache);
Object valueDescriptor = value == null ? null : createDescriptorIfAbsent(value, accessor, cache);
descriptor.setProperty(keyDescriptor, valueDescriptor);
});// ~ end of loop map
} else {
if (JavaBeanAccessor.isAccessByMethod(accessor)) {
Map<String, Method> methods = ReflectUtils.getBeanPropertyReadMethods(obj.getClass());
for (Map.Entry<String, Method> entry : methods.entrySet()) {
try {
Object value = entry.getValue().invoke(obj);
if (value == null) {
continue;
}
JavaBeanDescriptor valueDescriptor = createDescriptorIfAbsent(value, accessor, cache);
descriptor.setProperty(entry.getKey(), valueDescriptor);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
} // ~ end of loop method map
} // ~ end of if (JavaBeanAccessor.isAccessByMethod(accessor))
if (JavaBeanAccessor.isAccessByField(accessor)) {
Map<String, Field> fields = ReflectUtils.getBeanPropertyFields(obj.getClass());
for (Map.Entry<String, Field> entry : fields.entrySet()) {
if (!descriptor.containsProperty(entry.getKey())) {
try {
Object value = entry.getValue().get(obj);
if (value == null) {
continue;
}
JavaBeanDescriptor valueDescriptor = createDescriptorIfAbsent(value, accessor, cache);
descriptor.setProperty(entry.getKey(), valueDescriptor);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
} // ~ end of loop field map
} // ~ end of if (JavaBeanAccessor.isAccessByField(accessor))
} // ~ end of else
} // ~ end of method serializeInternal
public static Object deserialize(JavaBeanDescriptor beanDescriptor) {
return deserialize(
beanDescriptor,
Thread.currentThread().getContextClassLoader());
}
public static Object deserialize(JavaBeanDescriptor beanDescriptor, ClassLoader loader) {
if (beanDescriptor == null) {
return null;
}
IdentityHashMap<JavaBeanDescriptor, Object> cache = new IdentityHashMap<JavaBeanDescriptor, Object>();
Object result = instantiateForDeserialize(beanDescriptor, loader, cache);
deserializeInternal(result, beanDescriptor, loader, cache);
return result;
}
private static void deserializeInternal(Object result, JavaBeanDescriptor beanDescriptor, ClassLoader loader,
IdentityHashMap<JavaBeanDescriptor, Object> cache) {
if (beanDescriptor.isEnumType() || beanDescriptor.isClassType() || beanDescriptor.isPrimitiveType()) {
return;
}
if (beanDescriptor.isArrayType()) {
int index = 0;
for (Map.Entry<Object, Object> entry : beanDescriptor) {
Object item = entry.getValue();
if (item instanceof JavaBeanDescriptor) {
JavaBeanDescriptor itemDescriptor = (JavaBeanDescriptor) entry.getValue();
item = instantiateForDeserialize(itemDescriptor, loader, cache);
deserializeInternal(item, itemDescriptor, loader, cache);
}
Array.set(result, index++, item);
}
} else if (beanDescriptor.isCollectionType()) {
Collection collection = (Collection) result;
for (Map.Entry<Object, Object> entry : beanDescriptor) {
Object item = entry.getValue();
if (item instanceof JavaBeanDescriptor) {
JavaBeanDescriptor itemDescriptor = (JavaBeanDescriptor) entry.getValue();
item = instantiateForDeserialize(itemDescriptor, loader, cache);
deserializeInternal(item, itemDescriptor, loader, cache);
}
collection.add(item);
}
} else if (beanDescriptor.isMapType()) {
Map map = (Map) result;
for (Map.Entry<Object, Object> entry : beanDescriptor) {
Object key = entry.getKey();
Object value = entry.getValue();
if (key instanceof JavaBeanDescriptor) {
JavaBeanDescriptor keyDescriptor = (JavaBeanDescriptor) entry.getKey();
key = instantiateForDeserialize(keyDescriptor, loader, cache);
deserializeInternal(key, keyDescriptor, loader, cache);
}
if (value instanceof JavaBeanDescriptor) {
JavaBeanDescriptor valueDescriptor = (JavaBeanDescriptor) entry.getValue();
value = instantiateForDeserialize(valueDescriptor, loader, cache);
deserializeInternal(value, valueDescriptor, loader, cache);
}
map.put(key, value);
}
} else if (beanDescriptor.isBeanType()) {
for (Map.Entry<Object, Object> entry : beanDescriptor) {
String property = entry.getKey().toString();
Object value = entry.getValue();
if (value == null) {
continue;
}
if (value instanceof JavaBeanDescriptor) {
JavaBeanDescriptor valueDescriptor = (JavaBeanDescriptor) entry.getValue();
value = instantiateForDeserialize(valueDescriptor, loader, cache);
deserializeInternal(value, valueDescriptor, loader, cache);
}
Method method = getSetterMethod(result.getClass(), property, value.getClass());
boolean setByMethod = false;
try {
if (method != null) {
method.invoke(result, value);
setByMethod = true;
}
} catch (Exception e) {
LogHelper.warn(logger, "Failed to set property through method " + method, e);
}
if (!setByMethod) {
try {
Field field = result.getClass().getField(property);
if (field != null) {
field.set(result, value);
}
} catch (NoSuchFieldException | IllegalAccessException e1) {
LogHelper.warn(logger, "Failed to set field value", e1);
}
}
}
} else {
throw new IllegalArgumentException("Unsupported type " +
beanDescriptor.getClassName() +
":" + beanDescriptor.getType());
}
}
private static Method getSetterMethod(Class<?> cls, String property, Class<?> valueCls) {
String name = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);
Method method = null;
try {
method = cls.getMethod(name, valueCls);
} catch (NoSuchMethodException e) {
for (Method m : cls.getMethods()) {
if (ReflectUtils.isBeanPropertyWriteMethod(m)
&& m.getName().equals(name)) {
method = m;
}
}
}
if (method != null) {
method.setAccessible(true);
}
return method;
}
private static Object instantiate(Class<?> cl) throws Exception {
Constructor<?>[] constructors = cl.getDeclaredConstructors();
Constructor<?> constructor = null;
int argc = Integer.MAX_VALUE;
for (Constructor<?> c : constructors) {
if (c.getParameterTypes().length < argc) {
argc = c.getParameterTypes().length;
constructor = c;
}
}
if (constructor != null) {
Class<?>[] paramTypes = constructor.getParameterTypes();
Object[] constructorArgs = new Object[paramTypes.length];
for (int i = 0; i < constructorArgs.length; i++) {
constructorArgs[i] = getConstructorArg(paramTypes[i]);
}
try {
constructor.setAccessible(true);
return constructor.newInstance(constructorArgs);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
LogHelper.warn(logger, e.getMessage(), e);
}
}
return cl.getDeclaredConstructor().newInstance();
}
public static Object getConstructorArg(Class<?> cl) {
if (boolean.class.equals(cl) || Boolean.class.equals(cl)) {
return Boolean.FALSE;
}
if (byte.class.equals(cl) || Byte.class.equals(cl)) {
return (byte) 0;
}
if (short.class.equals(cl) || Short.class.equals(cl)) {
return (short) 0;
}
if (int.class.equals(cl) || Integer.class.equals(cl)) {
return 0;
}
if (long.class.equals(cl) || Long.class.equals(cl)) {
return 0L;
}
if (float.class.equals(cl) || Float.class.equals(cl)) {
return (float) 0;
}
if (double.class.equals(cl) || Double.class.equals(cl)) {
return (double) 0;
}
if (char.class.equals(cl) || Character.class.equals(cl)) {
return (char) 0;
}
return null;
}
private static Object instantiateForDeserialize(JavaBeanDescriptor beanDescriptor, ClassLoader loader,
IdentityHashMap<JavaBeanDescriptor, Object> cache) {
if (cache.containsKey(beanDescriptor)) {
return cache.get(beanDescriptor);
}
if (beanDescriptor.isClassType()) {
try {
return name2Class(loader, beanDescriptor.getClassNameProperty());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
if (beanDescriptor.isEnumType()) {
try {
Class<?> enumType = name2Class(loader, beanDescriptor.getClassName());
Method method = getEnumValueOfMethod(enumType);
return method.invoke(null, enumType, beanDescriptor.getEnumPropertyName());
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
if (beanDescriptor.isPrimitiveType()) {
return beanDescriptor.getPrimitiveProperty();
}
Object result;
if (beanDescriptor.isArrayType()) {
Class<?> componentType;
try {
componentType = name2Class(loader, beanDescriptor.getClassName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.getMessage(), e);
}
result = Array.newInstance(componentType, beanDescriptor.propertySize());
cache.put(beanDescriptor, result);
} else {
try {
Class<?> cl = name2Class(loader, beanDescriptor.getClassName());
result = instantiate(cl);
cache.put(beanDescriptor, result);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
return result;
}
/**
* Transform the Class.forName String to Class Object.
*
* @param name Class.getName()
* @return Class
* @throws ClassNotFoundException Class.forName
*/
public static Class<?> name2Class(ClassLoader loader, String name) throws ClassNotFoundException {
if (TYPES.containsKey(name)) {
return TYPES.get(name);
}
if (isArray(name)) {
int dimension = 0;
while (isArray(name)) {
++dimension;
name = name.substring(1);
}
Class type = name2Class(loader, name);
int[] dimensions = new int[dimension];
for (int i = 0; i < dimension; i++) {
dimensions[i] = 0;
}
return Array.newInstance(type, dimensions).getClass();
}
if (isReferenceType(name)) {
name = name.substring(1, name.length() - 1);
}
SerializeClassChecker.getInstance().validateClass(name);
return Class.forName(name, false, loader);
}
private static boolean isArray(String type) {
return type != null && type.startsWith(ARRAY_PREFIX);
}
private static boolean isReferenceType(String type) {
return type != null
&& type.startsWith(REFERENCE_TYPE_PREFIX)
&& type.endsWith(REFERENCE_TYPE_SUFFIX);
}
private static Method getEnumValueOfMethod(Class cl) throws NoSuchMethodException {
return cl.getMethod("valueOf", Class.class, String.class);
}
}
相关信息
相关文章
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦