jp.terasoluna.fw.util.GenericPropertyUtil.java Source code

Java tutorial

Introduction

Here is the source code for jp.terasoluna.fw.util.GenericPropertyUtil.java

Source

/*
 * Copyright (c) 2007 NTT DATA Corporation
 *
 * 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 jp.terasoluna.fw.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <code>JavaBean</code>?? <code>Generics</code>????
 */
public class GenericPropertyUtil {

    /**
     * 
     */
    private static final Log log = LogFactory.getLog(GenericPropertyUtil.class);

    /**
     * <code>JavaBean</code>? <code>Collection</code>?????
     * <p>
     * <h5>?</h5>
     * 
     * <pre>
     * <code>
     * public class Bean {
     *     private List&lt;String&gt; list;
     *     public List&lt;String&gt; getList() {
     *         return this.list;
     *     }
     * }
     * </code>
     * </pre>
     * 
     * ???<code>Bean</code>?????????? String.class????
     * 
     * <pre>
     * <code>
     * Bean bean = new Bean();
     * Class elementType =
     *     GenericCollectionUtil.resolveCollectionType(
     *         bean, "list");
     * </code>
     * </pre>
     *
     * @param bean <code>JavaBean</code>
     * @param name <code>Collection</code>????
     * @return <code>Collection</code>??? ???????<code>Object</code>???
     * @throws IllegalArgumentException <code>bean</code>? <code>null</code>??<code>name</code>? <code>null</code>
     *             ???? <code>JavaBean</code>?? ??????????
     * @throws IllegalStateException ???<code>Collection</code> ?????
     */
    public static Class<?> resolveCollectionType(Object bean, String name)
            throws IllegalArgumentException, IllegalStateException {
        return resolveType(bean, name, Collection.class, 0);
    }

    /**
     * <code>JavaBean</code>? <code>Generics</code>?????
     * <p>
     * <h5>?</h5>
     * 
     * <pre>
     * <code>
     * public class Bean {
     *     private Map&lt;String, Boolean&gt; map;
     *     public Map&lt;String, Boolean&gt; getMap() {
     *         return this.map;
     *     }
     * }
     * </code>
     * </pre>
     * 
     * ???<code>Bean</code>?????????? String.class????
     * 
     * <pre>
     * <code>
     * Bean bean = new Bean();
     * Class keyType =
     *     GenericCollectionUtil.resolveType(
     *         bean, "map", Map.class, 0);
     * </code>
     * </pre>
     *
     * @param bean <code>JavaBean</code>
     * @param name <code>Generics</code>????
     * @param genericClass <code>Generics</code>? ???
     * @param index ??
     * @return <code>Generics</code>??? ???????<code>Object</code>???
     * @throws IllegalArgumentException <code>bean</code>? <code>null</code>??<code>name</code>? <code>null</code>
     *             ???? <code>genericClass</code>?<code>null</code>?? <code>index</code>?<code>0</code>
     *             ???????? ???? <code>JavaBean</code>?? ??????????
     * @throws IllegalStateException ?<code>WildCardType</code>???
     */
    public static Class<?> resolveType(Object bean, String name, Class<?> genericClass, int index)
            throws IllegalArgumentException, IllegalStateException {
        if (bean == null) {
            throw new IllegalArgumentException("Argument 'bean' (" + Object.class.getName() + " is null");
        }
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("Argument 'name' (" + String.class.getName() + " is empty");
        }

        Method method = getMethod(bean, name);
        return resolveType(genericClass, method.getReturnType(), method.getGenericReturnType(), index);
    }

    /**
     * <code>JavaBean</code>??? ??
     * @param bean <code>JavaBean</code>
     * @param name <code>Generics</code>????
     * @return <code>JavaBean</code>?????
     * @throws IllegalArgumentException <code>JavaBean</code>?? ??????????
     */
    protected static Method getMethod(Object bean, String name) throws IllegalArgumentException {
        PropertyDescriptor descriptor = null;
        try {
            descriptor = PropertyUtils.getPropertyDescriptor(bean, name);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException(
                    "Failed to detect getter for " + bean.getClass().getName() + "#" + name, e);
        } catch (InvocationTargetException e) {
            throw new IllegalArgumentException(
                    "Failed to detect getter for " + bean.getClass().getName() + "#" + name, e);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(
                    "Failed to detect getter for " + bean.getClass().getName() + "#" + name, e);
        }
        Method method = null;
        if (descriptor != null) {
            method = descriptor.getReadMethod();
        }
        if (method == null) {
            throw new IllegalArgumentException(bean.getClass().getName() + " has no getter for property " + name);
        }
        return method;
    }

    /**
     * ??????? <code>Generics</code>?????
     * @param genericClass <code>Generics</code>? ???
     * @param clazz ???
     * @param type ????? <code>Type</code>
     * @param index ??
     * @return <code>Generics</code>??? ???????<code>Object</code>???
     * @throws IllegalArgumentException <code>genericClass</code>? <code>null</code>?? <code>clazz</code>?
     *             <code>null</code>?? <code>index</code>?<code>0</code>???????? ????
     * @throws IllegalStateException ?<code>WildCardType</code>???
     */
    @SuppressWarnings("unchecked")
    protected static Class<?> resolveType(Class<?> genericClass, @SuppressWarnings("rawtypes") Class clazz,
            Type type, int index) throws IllegalArgumentException, IllegalStateException {
        if (genericClass == null) {
            throw new IllegalArgumentException("Argument 'genericsClass' (" + Class.class.getName() + ") is null");
        }
        if (clazz == null || !genericClass.isAssignableFrom(clazz)) {
            throw new IllegalStateException(genericClass + " is not assignable from " + clazz);
        }

        List<ParameterizedType> ancestorTypeList = null;
        try {
            ancestorTypeList = GenericsUtil.getAncestorTypeList(genericClass, clazz);
        } catch (IllegalStateException e) {
            if (log.isTraceEnabled()) {
                log.trace(e.getMessage());
            }
        }
        if (ancestorTypeList == null) {
            ancestorTypeList = new ArrayList<ParameterizedType>();
        }
        if (type instanceof ParameterizedType) {
            ancestorTypeList.add(0, (ParameterizedType) type);
        }
        if (ancestorTypeList.size() <= 0) {
            throw new IllegalStateException("No parameterizedType was detected.");
        }
        ParameterizedType parameterizedType = ancestorTypeList.get(ancestorTypeList.size() - 1);
        Type[] actualTypes = parameterizedType.getActualTypeArguments();

        // ??????
        if (index < 0 || index >= actualTypes.length) {
            throw new IllegalArgumentException("Argument 'index'(" + Integer.toString(index)
                    + ") is out of bounds of" + " generics parameters");
        }

        Class<?> resolved = Object.class;
        try {
            resolved = GenericsUtil.resolveTypeVariable(actualTypes[index], ancestorTypeList);
        } catch (IllegalStateException e) {
            if (log.isTraceEnabled()) {
                log.trace(e.getMessage());
            }
        }
        return resolved;
    }

}