All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.dubbo.common.beanutil.JavaBeanSerializeUtil Maven / Gradle / Ivy

/*
 * Copyright 1999-2012 Alibaba Group.
 *
 * Licensed 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 com.alibaba.dubbo.common.beanutil;

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;

import lombok.extern.slf4j.Slf4j;
import net.jahhan.com.alibaba.dubbo.common.utils.ReflectUtils;

/**
 * @author kimi
 */
@Slf4j
public final class JavaBeanSerializeUtil {

	public static JavaBeanDescriptor serialize(Object obj) {
		JavaBeanDescriptor result = serialize(obj, JavaBeanAccessor.FIELD);
		return result;
	}

	public static JavaBeanDescriptor serialize(Object obj, JavaBeanAccessor accessor) {
		if (obj == null) {
			return null;
		}
		if (obj instanceof JavaBeanDescriptor) {
			return (JavaBeanDescriptor) obj;
		}
		IdentityHashMap cache = new IdentityHashMap();
		JavaBeanDescriptor result = createDescriptorIfAbsent(obj, accessor, cache);
		return result;
	}

	private static JavaBeanDescriptor createDescriptorForSerialize(Class cl) {
		if (cl.isEnum()) {
			return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_ENUM);
		} else if (cl.isArray()) {
			return new JavaBeanDescriptor(cl.getComponentType().getName(), JavaBeanDescriptor.TYPE_ARRAY);
		} else if (ReflectUtils.isPrimitive(cl)) {
			return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);
		} else if (Class.class.equals(cl)) {
			return new JavaBeanDescriptor(Class.class.getName(), JavaBeanDescriptor.TYPE_CLASS);
		} else if (Collection.class.isAssignableFrom(cl)) {
			return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_COLLECTION);
		} else if (Map.class.isAssignableFrom(cl)) {
			return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_MAP);
		} else {
			return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_BEAN);
		}
	}

	private static JavaBeanDescriptor createDescriptorIfAbsent(Object obj, JavaBeanAccessor accessor,
			IdentityHashMap cache) {
		if (cache.containsKey(obj)) {
			return cache.get(obj);
		} else if (obj instanceof JavaBeanDescriptor) {
			return (JavaBeanDescriptor) obj;
		} else {
			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 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;
			for (Object key : map.keySet()) {
				Object value = map.get(key);
				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 methods = ReflectUtils.getBeanPropertyReadMethods(obj.getClass());
				for (Map.Entry 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 fields = ReflectUtils.getBeanPropertyFields(obj.getClass());
				for (Map.Entry 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) {
		Object result = deserialize(beanDescriptor, Thread.currentThread().getContextClassLoader());
		return result;
	}

	public static Object deserialize(JavaBeanDescriptor beanDescriptor, ClassLoader loader) {
		if (beanDescriptor == null) {
			return null;
		}
		IdentityHashMap cache = new IdentityHashMap();
		Object result = instantiateForDeserialize(beanDescriptor, loader, cache);
		deserializeInternal(result, beanDescriptor, loader, cache);
		return result;
	}

	private static void deserializeInternal(Object result, JavaBeanDescriptor beanDescriptor, ClassLoader loader,
			IdentityHashMap cache) {
		if (beanDescriptor.isEnumType() || beanDescriptor.isClassType() || beanDescriptor.isPrimitiveType()) {
			return;
		}

		if (beanDescriptor.isArrayType()) {
			int index = 0;
			for (Map.Entry 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 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 entry : beanDescriptor) {
				Object key = entry.getKey();
				Object value = entry.getValue();
				if (key != null && key instanceof JavaBeanDescriptor) {
					JavaBeanDescriptor keyDescriptor = (JavaBeanDescriptor) entry.getKey();
					key = instantiateForDeserialize(keyDescriptor, loader, cache);
					deserializeInternal(key, keyDescriptor, loader, cache);
				}
				if (value != null && 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 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) {
					log.warn("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 e1) {
						log.warn("Failed to set field value", e1);
					} catch (IllegalAccessException e1) {
						log.warn("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 e) {
				log.warn(e.getMessage(), e);
			} catch (IllegalAccessException e) {
				log.warn(e.getMessage(), e);
			} catch (InvocationTargetException e) {
				log.warn(e.getMessage(), e);
			}
		}

		return cl.newInstance();
	}

	private static Object getConstructorArg(Class cl) {
		if (boolean.class.equals(cl) || Boolean.class.equals(cl)) {
			return Boolean.FALSE;
		} else if (byte.class.equals(cl) || Byte.class.equals(cl)) {
			return Byte.valueOf((byte) 0);
		} else if (short.class.equals(cl) || Short.class.equals(cl)) {
			return Short.valueOf((short) 0);
		} else if (int.class.equals(cl) || Integer.class.equals(cl)) {
			return Integer.valueOf(0);
		} else if (long.class.equals(cl) || Long.class.equals(cl)) {
			return Long.valueOf(0L);
		} else if (float.class.equals(cl) || Float.class.equals(cl)) {
			return Float.valueOf((float) 0);
		} else if (double.class.equals(cl) || Double.class.equals(cl)) {
			return Double.valueOf((double) 0);
		} else if (char.class.equals(cl) || Character.class.equals(cl)) {
			return new Character((char) 0);
		} else {
			return null;
		}
	}

	private static Object instantiateForDeserialize(JavaBeanDescriptor beanDescriptor, ClassLoader loader,
			IdentityHashMap cache) {
		if (cache.containsKey(beanDescriptor)) {
			return cache.get(beanDescriptor);
		}
		Object result = null;
		if (beanDescriptor.isClassType()) {
			try {
				result = name2Class(loader, beanDescriptor.getClassNameProperty());
				return result;
			} catch (ClassNotFoundException e) {
				throw new RuntimeException(e.getMessage(), e);
			}
		} else if (beanDescriptor.isEnumType()) {
			try {
				Class enumType = name2Class(loader, beanDescriptor.getClassName());
				Method method = getEnumValueOfMethod(enumType);
				result = method.invoke(null, enumType, beanDescriptor.getEnumPropertyName());
				return result;
			} catch (Exception e) {
				throw new RuntimeException(e.getMessage(), e);
			}
		} else if (beanDescriptor.isPrimitiveType()) {
			result = beanDescriptor.getPrimitiveProperty();
			return result;
		} else 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 (ClassNotFoundException e) {
				throw new RuntimeException(e.getMessage(), e);
			} catch (Exception e) {
				throw new RuntimeException(e.getMessage(), e);
			}

		return result;
	}

	private static final Map> TYPES = new HashMap>();

	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 static final String ARRAY_PREFIX = "[";

	private static final String REFERENCE_TYPE_PREFIX = "L";

	private static final String REFERENCE_TYPE_SUFFIX = ";";

	/**
	 * 把 Class.forName 的返回值转换为 Class.
	 *
	 * @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);
		}
		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);
	}

	private JavaBeanSerializeUtil() {
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy