com.feilong.core.bean.PropertyUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.feilong.core.bean.PropertyUtil.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * 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.feilong.core.bean;

import java.util.Collection;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.core.lang.ClassUtil;

import static com.feilong.core.Validator.isNotNullOrEmpty;
import static com.feilong.core.Validator.isNullOrEmpty;
import static com.feilong.core.util.MapUtil.newLinkedHashMap;

/**
 *  {@link org.apache.commons.beanutils.PropertyUtils}??.
 * 
 * <p>
 * ? checkedException  ?? {@link BeanUtilException}
 * </p>
 * 
 * <h3>{@link PropertyUtils} {@link BeanUtils}:</h3>
 * 
 * <blockquote>
 * <p>
 * {@link PropertyUtils}{@link BeanUtils}??,??.<br>
 * {@link BeanUtils}??"Bean",{@link String},<br>
 * {@link PropertyUtils}??,{@link Object}.
 * </p>
 * </blockquote>
 * 
 * @author <a href="http://feitianbenyue.iteye.com/">feilong</a>
 * @see org.apache.commons.beanutils.PropertyUtils
 * @see com.feilong.core.bean.BeanUtil
 * @since 1.0.0
 */
public final class PropertyUtil {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory.getLogger(PropertyUtil.class);

    /** Don't let anyone instantiate this class. */
    private PropertyUtil() {
        //AssertionError?. ?????. ???.
        //see Effective Java 2nd
        throw new AssertionError("No " + getClass().getName() + " instances for you!");
    }

    /**
     * <code>fromObj</code>,?<code>toObj</code>.
     * 
     * <h3>??:</h3>
     * <blockquote>
     * <p>
     * <code>includePropertyNames</code>?,{@link PropertyUtils#copyProperties(Object, Object)},<br>
     * ? {@link #getProperty(Object, String)}?{@link #setProperty(Object, String, Object)}<code>toObj</code>
     * </p>
     * </blockquote>
     * 
     * <h3>?:</h3>
     * 
     * <blockquote>
     * 
     * <ol>
     * <li> <code>toObj</code> null, {@link NullPointerException}</li>
     * <li> <code>fromObj</code> null, {@link NullPointerException}</li>
     * <li><code>includePropertyNames</code>,? <code>fromObj</code>??,</li>
     * <li><code>includePropertyNames</code>,? <code>fromObj</code>, <code>toObj</code>??,,see
     * {@link PropertyUtilsBean#setSimpleProperty(Object, String, Object) copyProperties} Line2078</li>
     * <li>Date,<span style="color:red">??converter</span></li>
     * <li>?copy <span style="color:red">?</span>,??2Bean???ref,??, .</li>
     * </ol>
     * </blockquote>
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * User oldUser = new User();
     * oldUser.setId(5L);
     * oldUser.setMoney(new BigDecimal(500000));
     * oldUser.setDate(new Date());
     * oldUser.setNickName(ConvertUtil.toArray("feilong", "", "venusdrogon"));
     * 
     * User newUser = new User();
     * PropertyUtil.copyProperties(newUser, oldUser, "date", "money", "nickName");
     * LOGGER.debug(JsonUtil.format(newUser));
     * </pre>
     * 
     *  :
     * 
     * <pre class="code">
     * {
    "date": "2015-09-06 13:27:43",
    "id": 0,
    "nickName":         [
        "feilong",
        "",
        "venusdrogon"
    ],
    "age": 0,
    "name": "feilong",
    "money": 500000,
    "userInfo": {"age": 0}
    }
     * </pre>
     * 
     * </blockquote>
     * 
     * <h3>{@link BeanUtils#copyProperties(Object, Object)} {@link PropertyUtils#copyProperties(Object, Object)}</h3>
     * 
     * <blockquote>
     * <ul>
     * <li>{@link BeanUtils#copyProperties(Object, Object) BeanUtils} ???,??JavaBean?????,???,<br>
     *  {@link PropertyUtils#copyProperties(Object, Object) PropertyUtils}??,.</li>
     * <li>commons-beanutils v1.9.0? BeanUtils?? null,PropertyUtils?? null.<br>
     * (<b>:</b>commons-beanutils v1.9.0+?,BeanUtilsBean.copyProperties() no longer throws a ConversionException for null properties
     * of certain data types),?commons-beanutils
     * <a href="http://commons.apache.org/proper/commons-beanutils/javadocs/v1.9.2/RELEASE-NOTES.txt">RELEASE-NOTES.txt</a></li>
     * </ul>
     * </blockquote>
     * 
     * @param toObj
     *            
     * @param fromObj
     *            
     * @param includePropertyNames
     *            ???,(can be nested/indexed/mapped/combo)<br>
     *            nullempty, {@link PropertyUtils#copyProperties(Object, Object)}
     * @see #setProperty(Object, String, Object)
     * @see BeanUtil#copyProperties(Object, Object, String...)
     * @see org.apache.commons.beanutils.PropertyUtilsBean#copyProperties(Object, Object)
     * @see <a href="http://www.cnblogs.com/kaka/archive/2013/03/06/2945514.html">Bean??(Apache BeanUtils?PropertyUtils,Spring
     *      BeanUtils,Cglib BeanCopier)</a>
     * @since 1.4.1
     */
    public static void copyProperties(Object toObj, Object fromObj, String... includePropertyNames) {
        Validate.notNull(toObj, "toObj [destination bean] not specified!");
        Validate.notNull(fromObj, "fromObj [origin bean] not specified!");

        if (isNullOrEmpty(includePropertyNames)) {
            try {
                PropertyUtils.copyProperties(toObj, fromObj);
                return;
            } catch (Exception e) {
                throw new BeanUtilException(e);
            }
        }
        for (String propertyName : includePropertyNames) {
            Object value = getProperty(fromObj, propertyName);
            setProperty(toObj, propertyName, value);
        }
    }

    /**
     *  <code>bean</code> <code>propertyNames</code><span style="color:green">?</span>,??/
     * {@link java.util.LinkedHashMap LinkedHashMap} .
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * User user = new User();
     * user.setId(5L);
     * user.setDate(new Date());
     * 
     * LOGGER.debug("map:{}", JsonUtil.format(PropertyUtil.describe(user)));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
    {
        "id": 5,
        "name": "feilong",
        "age": null,
        "date": "2016-07-13 22:18:26"
    }
     * </pre>
     * 
     * <hr>
     * 
     * <p>
     * ???:
     * </p>
     * 
     * <pre class="code">
     * 
     * User user = new User();
     * user.setId(5L);
     * user.setDate(new Date());
     * 
     * LOGGER.debug("map:{}", JsonUtil.format(PropertyUtil.describe(user, "date", "id")));
     * 
     * </pre>
     * 
     * ????:
     * 
     * <pre class="code">
    {
    "date": "2016-07-13 22:21:24",
    "id": 5
    }
     * </pre>
     * 
     * </blockquote>
     * 
     * <h3>:</h3>
     * <blockquote>
     * <ol>
     * <li> the entire set of properties for which the specified bean provides a read method.</li>
     * <li>???class,Object??,classjava.lang.Object</li>
     * <li> <code>propertyNames</code>null empty,?</li>
     * <li>mapkey <code>propertyNames</code> ?</li>
     * </ol>
     * </blockquote>
     * 
     * <h3>?:</h3>
     * 
     * <blockquote>
     * <ol>
     * <li>?bean class {@link java.beans.PropertyDescriptor}</li>
     * <li>, {@link java.beans.PropertyDescriptor#getReadMethod()}</li>
     * <li> name and {@link org.apache.commons.beanutils.PropertyUtilsBean#getProperty(Object, String)} map</li>
     * </ol>
     * </blockquote>
     *
     * @param bean
     *            Bean whose properties are to be extracted
     * @param propertyNames
     *            ?? (can be nested/indexed/mapped/combo),?? <a href="../BeanUtil.html#propertyName">propertyName</a>
     * @return  <code>propertyNames</code> nullempty, {@link PropertyUtils#describe(Object)}<br>
     * @throws NullPointerException
     *              <code>bean</code> null
     * @see org.apache.commons.beanutils.BeanUtils#describe(Object)
     * @see org.apache.commons.beanutils.PropertyUtils#describe(Object)
     * @since 1.8.0
     */
    public static Map<String, Object> describe(Object bean, String... propertyNames) {
        Validate.notNull(bean, "bean can't be null!");
        if (isNullOrEmpty(propertyNames)) {
            try {
                return PropertyUtils.describe(bean);
            } catch (Exception e) {
                throw new BeanUtilException(e);
            }
        }
        Map<String, Object> map = newLinkedHashMap(propertyNames.length);
        for (String propertyName : propertyNames) {
            map.put(propertyName, getProperty(bean, propertyName));
        }
        return map;
    }

    /**
     *  {@link PropertyUtils#setProperty(Object, String, Object)} ?bean(<b>??</b>).
     * 
     * <p>
     * no matter which property reference format is used, with no type conversions.
     * </p>
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * User newUser = new User();
     * PropertyUtil.setProperty(newUser, "name", "feilong");
     * LOGGER.info(JsonUtil.format(newUser));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "age": 0,
     * "name": "feilong"
     * }
     * </pre>
     * 
     * </blockquote>
     * 
     * <h3>?:</h3>
     * 
     * <blockquote>
     * 
     * <ol>
     * <li> <code>bean</code> null, {@link NullPointerException}</li>
     * <li> <code>propertyName</code> null, {@link NullPointerException}</li>
     * <li> <code>propertyName</code> blank, {@link IllegalArgumentException}</li>
     * <li><code>bean</code> <code>propertyName</code>??,,see
     * {@link PropertyUtilsBean#setSimpleProperty(Object, String, Object) setSimpleProperty} Line2078</li>
     * <li>Date,<span style="color:red">??converter</span></li>
     * </ol>
     * </blockquote>
     *
     * @param bean
     *            Bean whose property is to be modified
     * @param propertyName
     *            ?? (can be nested/indexed/mapped/combo),?? <a href="../BeanUtil.html#propertyName">propertyName</a>
     * @param value
     *            Value to which this property is to be set
     * @see org.apache.commons.beanutils.BeanUtils#setProperty(Object, String, Object)
     * @see org.apache.commons.beanutils.PropertyUtils#setProperty(Object, String, Object)
     * @see BeanUtil#setProperty(Object, String, Object)
     */
    public static void setProperty(Object bean, String propertyName, Object value) {
        Validate.notNull(bean, "bean can't be null!");
        Validate.notBlank(propertyName, "propertyName can't be null!");
        try {
            PropertyUtils.setProperty(bean, propertyName, value);
        } catch (Exception e) {
            throw new BeanUtilException(e);
        }
    }

    /**
     *  <code>value</code> isNotNullOrEmpty,? {@link #setProperty(Object, String, Object)}.
     * 
     * <h3>?:</h3>
     * 
     * <blockquote>
     * 
     * <ol>
     * <li> <code>bean</code> null, {@link NullPointerException}</li>
     * <li> <code>propertyName</code> null, {@link NullPointerException}</li>
     * <li> <code>propertyName</code> blank, {@link IllegalArgumentException}</li>
     * <li><code>bean</code> <code>propertyName</code>??,,see
     * {@link PropertyUtilsBean#setSimpleProperty(Object, String, Object)} Line2078</li>
     * <li>Date,<span style="color:red">??converter</span></li>
     * </ol>
     * </blockquote>
     *
     * @param bean
     *            Bean whose property is to be modified
     * @param propertyName
     *            ?? (can be nested/indexed/mapped/combo),?? <a href="../BeanUtil.html#propertyName">propertyName</a>
     * @param value
     *            Value to which this property is to be set
     * @since 1.5.3
     */
    public static void setPropertyIfValueNotNullOrEmpty(Object bean, String propertyName, Object value) {
        if (isNotNullOrEmpty(value)) {
            setProperty(bean, propertyName, value);
        }
    }

    /**
     *  <code>null != value</code>,? {@link #setProperty(Object, String, Object)}.
     * 
     * <h3>?:</h3>
     * 
     * <blockquote>
     * 
     * <ol>
     * <li> <code>bean</code> null, {@link NullPointerException}</li>
     * <li> <code>propertyName</code> null, {@link NullPointerException}</li>
     * <li> <code>propertyName</code> blank, {@link IllegalArgumentException}</li>
     * <li><code>bean</code> <code>propertyName</code>??,,see
     * {@link PropertyUtilsBean#setSimpleProperty(Object, String, Object)} Line2078</li>
     * <li>Date,<span style="color:red">??converter</span></li>
     * </ol>
     * </blockquote>
     *
     * @param bean
     *            Bean whose property is to be modified
     * @param propertyName
     *            ?? (can be nested/indexed/mapped/combo),?? <a href="../BeanUtil.html#propertyName">propertyName</a>
     * @param value
     *            Value to which this property is to be set
     * @see #setProperty(Object, String, Object)
     * @since 1.5.3
     */
    public static void setPropertyIfValueNotNull(Object bean, String propertyName, Object value) {
        if (null != value) {
            setProperty(bean, propertyName, value);
        }
    }

    // [start] getProperty

    /**
     *  {@link PropertyUtils#getProperty(Object, String)} bean???.
     * 
     * <p>
     * no matter which property reference format is used, with no type conversions.<br>
     * For more details see {@link PropertyUtilsBean}.
     * </p>
     *
     * @param <T>
     *            the generic type
     * @param bean
     *            Bean whose property is to be extracted
     * @param propertyName
     *            ?? (can be nested/indexed/mapped/combo),?? <a href="../BeanUtil.html#propertyName">propertyName</a>
     * @return  <code>bean</code> null, {@link NullPointerException}<br>
     *          <code>propertyName</code> null, {@link NullPointerException}<br>
     *          <code>propertyName</code> blank, {@link IllegalArgumentException}<br>
     *         ? {@link PropertyUtils#getProperty(Object, String)} ?
     * @see BeanUtil#getProperty(Object, String)
     * @see org.apache.commons.beanutils.BeanUtils#getProperty(Object, String)
     * @see org.apache.commons.beanutils.PropertyUtils#getProperty(Object, String)
     * @see org.apache.commons.beanutils.PropertyUtilsBean
     */
    @SuppressWarnings("unchecked")
    public static <T> T getProperty(Object bean, String propertyName) {
        Validate.notNull(bean, "bean can't be null!");
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        try {
            return (T) PropertyUtils.getProperty(bean, propertyName);
        } catch (Exception e) {
            throw new BeanUtilException(e);
        }
    }

    // [end]

    /**
     *  <code>Object obj</code>,.
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * User user = new User();
     * user.setId(5L);
     * Date now = new Date();
     * user.setDate(now);
     * 
     * user.getUserInfo().setAge(28);
     * 
     * LOGGER.info(JsonUtil.format(PropertyUtil.findValueOfType(user, UserInfo.class)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {"age": 28}
     * </pre>
     * 
     * </blockquote>
     * 
     * <h3>??:</h3>
     * 
     * <blockquote>
     * <ol>
     * <li> <code>ClassUtil.isInstance(findValue, toBeFindedClassType)</code>  findValue</li>
     * <li><code>isPrimitiveOrWrapper</code>,<code>CharSequence</code>,<code>Collection</code>,<code>Map</code></li>
     * <li> {@link PropertyUtil#describe(Object, String...)} ?</li>
     * </ol>
     * </blockquote>
     * 
     * <p>
     * PS:?????,?? {@link #isDonotSupportFindType(Object)},,? {@link
     * "org.springframework.util.CollectionUtils#findValueOfType(Collection, Class)"}
     * </p>
     *
     * @param <T>
     *            the generic type
     * @param obj
     *            ?
     * @param toBeFindedClassType
     *            the to be finded class type
     * @return ?,? <code>null</code><br>
     *          <code>obj</code> null,null<br>
     *          <code>toBeFindedClassType</code> null, {@link NullPointerException}<br>
     *          <code>ClassUtil.isInstance(obj, toBeFindedClassType)</code>, <code>obj</code><br>
     * @see "org.springframework.util.CollectionUtils#findValueOfType(Collection, Class)"
     * @since 1.4.1
     */
    @SuppressWarnings("unchecked")
    public static <T> T findValueOfType(Object obj, Class<T> toBeFindedClassType) {
        if (isNullOrEmpty(obj)) {
            return null;
        }

        Validate.notNull(toBeFindedClassType, "toBeFindedClassType can't be null/empty!");

        if (ClassUtil.isInstance(obj, toBeFindedClassType)) {
            return (T) obj;
        }

        if (isDonotSupportFindType(obj)) {
            LOGGER.debug("obj:[{}] not support find toBeFindedClassType:[{}]", obj.getClass().getName(),
                    toBeFindedClassType.getName());
            return null;
        }

        //******************************************************************************
        Map<String, Object> describe = describe(obj);

        for (Map.Entry<String, Object> entry : describe.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if (null != value && !"class".equals(key)) {
                //?
                T t = findValueOfType(value, toBeFindedClassType);
                if (null != t) {
                    return t;
                }
            }
        }
        return null;
    }

    /**
     * command ?  string int,list map.
     * 
     * <p>
     * ,?? findedClassType
     * </p>
     * 
     * @param obj
     *            the obj
     * @return true, if checks if is can find type
     * @since 1.6.3
     */
    private static boolean isDonotSupportFindType(Object obj) {
        //command ?  string int,list map
        //,?? findedClassType
        return ClassUtils.isPrimitiveOrWrapper(obj.getClass())//
                || ClassUtil.isInstanceAnyClass(obj, CharSequence.class, Collection.class, Map.class);
    }
}