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

net.dongliu.commons.reflect.Beans Maven / Gradle / Ivy

There is a newer version: 12.0.2
Show newest version
package net.dongliu.commons.reflect;

import net.dongliu.commons.collection.Lists;
import net.dongliu.commons.collection.Maps;
import net.dongliu.commons.collection.Pair;
import net.dongliu.commons.concurrent.WeakLoader;
import net.dongliu.commons.exception.ReflectException;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * Utils method to deal with java bean
 *
 * @author Liu Dong {@literal }
 */
public class Beans {

    private static final WeakLoader, Class>, BeanCopier> copierCacheLoader
            = WeakLoader.create(pair -> getBeanCopier(pair.first(), pair.second()));
    private static final WeakLoader, List> propertiesCacheLoader
            = WeakLoader.create(Beans::getPropertyDescriptors);

    /**
     * Convert bean to map.
     *
     * @return null if bean is null, other wise map contains the key-load entries from bean's properties
     */
    public static Map toMap(Object bean) throws ReflectException {
        Map map = Maps.create();
        List pds = getProperties(bean);
        for (BeanProperty pd : pds) {
            String name = pd.name();
            if (!pd.canRead()) {
                continue;
            }
            Object value = pd.get(bean);
            map.put(name, value);
        }
        return map;
    }

    /**
     * Convert map to bean
     *
     * @return null if map is null; other wise bean with properties values from map
     */
    public static  T copyFromMap(Map map, Class cls) {
        T bean = newBean(cls);
        copyPropertiesFromMap(map, bean);
        return bean;
    }

    /**
     * Set bean properties with values from map
     *
     * @param bean not null
     */
    public static  void copyPropertiesFromMap(Map map, T bean) {
        List properties = getProperties(bean);
        for (BeanProperty property : properties) {
            String name = property.name();
            if (!map.containsKey(name)) {
                continue;
            }
            if (!property.canWrite()) {
                continue;
            }
            property.set(bean, map.get(name));
        }
    }

    /**
     * Shallow copy bean via reflect
     */
    @SuppressWarnings("unchecked")
    public static  T copyBean(T bean) {
        T newBean;
        try {
            newBean = (T) bean.getClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ReflectException(e);
        }
        copyBeanProperties(bean, newBean);
        return bean;
    }

    /**
     * Shallow copy bean
     */
    public static void copyBeanProperties(Object src, Object dst) {
        Pair, Class> key = Pair.of(src.getClass(), dst.getClass());
        BeanCopier beanCopier = copierCacheLoader.get(key);
        beanCopier.copy(src, dst);
    }

    private static BeanCopier getBeanCopier(Class srcClass, Class dstClass) {
        List srcPdList = getClassProperties(srcClass);
        List dstPdList = getClassProperties(dstClass);
        Map dstMap = new HashMap<>();
        for (BeanProperty pd : dstPdList) {
            if (!pd.canWrite()) {
                continue;
            }
            String dstName = pd.name();
            dstMap.put(dstName, pd);
        }
        List> matchList = new ArrayList<>();
        for (BeanProperty pd : srcPdList) {
            if (!pd.canRead()) {
                continue;
            }
            String srcName = pd.name();
            Class srcType = pd.type();
            BeanProperty dstPd = dstMap.get(srcName);
            if (dstPd != null) {
                Class dstType = dstPd.type();
                if (dstType.isAssignableFrom(srcType)) {
                    matchList.add(Pair.of(pd, dstPd));
                }
            }
        }
        return new BeanCopier(matchList);
    }

    /**
     * Convert bean to String.
     * Note: this method use declared fields to construct string ,not use properties
     */
    public static String toString(Object bean) {
        StringJoiner joiner = new StringJoiner(", ", bean.getClass().getSimpleName() + "{", "}");
        for (Field field : getFields(bean.getClass())) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            String name = field.getName();
            Object value;
            try {
                value = field.get(bean);
            } catch (IllegalAccessException e) {
                throw new ReflectException(e);
            }
            joiner.add(name + "=" + String.valueOf(value));
        }
        return joiner.toString();
    }

    private static  T newBean(Class cls) {
        try {
            return cls.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ReflectException(e);
        }
    }

    /**
     * Get bean properties
     *
     * @return Immutable property list
     * @throws ReflectException
     */
    public static List getProperties(Object bean) {
        Class cls = bean.getClass();
        return getClassProperties(cls);
    }

    /**
     * Get all fields for class.
     */
    public static List getFields(Class cls) {
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
        }
        return Lists.of(fields);
    }

    /**
     * Get bean class properties
     *
     * @return Immutable property list
     * @throws ReflectException
     */
    public static List getClassProperties(Class cls) {
        return propertiesCacheLoader.get(cls);
    }

    private static List getPropertyDescriptors(Class cls) {
        return Lists.wrapImmutable(JavaClass.of(cls).getAllProperties());
    }

    static class BeanCopier {
        private final List> matchList;

        BeanCopier(List> matchList) {
            this.matchList = matchList;
        }

        void copy(Object src, Object dst) {
            for (Pair pair : matchList) {
                Object value = pair.first().get(src);
                pair.second().set(dst, value);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy