jef.tools.reflect.ClassEx.java Source code

Java tutorial

Introduction

Here is the source code for jef.tools.reflect.ClassEx.java

Source

/*
 * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
 *
 * 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 jef.tools.reflect;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.management.ReflectionException;

import jef.common.log.LogUtil;
import jef.tools.Assert;
import jef.tools.StringUtils;
import jef.tools.collection.CollectionUtil;
import jef.tools.collection.IterableAccessor;
import jef.tools.reflect.BeanUtils.SearchMode;

import org.apache.commons.lang.ObjectUtils;

/**
 * Class?
 * ??Class?
 * @author jiyi
 */
public class ClassEx {
    /**
     * Class
     */
    private Class<?> cls;
    /**
     * 
     */
    private Type genericType;

    private ClassEx instanceClz;

    public ClassEx(Type type) {
        this.genericType = type;
        this.cls = GenericUtils.getRawClass(type);
        Assert.notNull(cls);
    }

    public ClassEx(Class<?> cls) {
        if (isCGLibProxy(cls)) {
            cls = cls.getSuperclass();
        }
        this.genericType = cls;
        this.cls = cls;
    }

    /**
     * 
     * 
     * @return
     */
    public Class<?> getWrappered() {
        return cls;
    }

    /**
     * 
     * 
     * @return
     */
    public Type getGenericType() {
        return genericType;
    }

    /**
     * ??
     * 
     * @param params
     * @return
     * @throws ReflectionException
     */
    public Object newInstance(Object... params) throws ReflectionException {
        return BeanUtils.newInstance(cls, params);
    }

    /**
     * ??null
     */
    public Object newInstanceAnyway() throws ReflectionException {
        return BeanUtils.newInstanceAnyway(cls);
    }

    /**
     * ???
     * 
     * @param method
     * @param params
     * @return
     * @throws ReflectionException
     */
    public Object invokeStaticMethod(String method, Object... params) throws ReflectionException {
        return innerInvoke(null, method, true, params);
    }

    /**
     * ????
     * 
     * @param method
     * @param params
     * @return
     * @throws ReflectionException
     */
    public Object invokeWithNewInstance(String method, Object... params) throws ReflectionException {
        return innerInvoke(newInstanceAnyway(), method, false, params);
    }

    /*
     * obj method??isStatic??params:?
     */
    Object innerInvoke(Object obj, String method, boolean isStatic, Object... params) throws ReflectionException {
        try {
            if (obj == null && !isStatic)
                obj = newInstance();
            List<Class<?>> list = new ArrayList<Class<?>>();
            for (Object pobj : params) {
                list.add(pobj.getClass());
            }
            MethodEx me = BeanUtils.getCompatibleMethod(cls, method, list.toArray(new Class[list.size()]));
            if (me == null) {
                NoSuchMethodException e = new NoSuchMethodException("Method:[" + cls.getName() + "::" + method
                        + "] not found with param count:" + params.length);
                throw new ReflectionException(e);
            }
            if (!Modifier.isPublic(me.getModifiers()) || !Modifier.isPublic(cls.getModifiers())) {
                try {
                    me.setAccessible(true);
                } catch (SecurityException e) {
                    System.out.println(me.toString() + "\n" + e.getMessage());
                }
            }
            return me.invoke(obj, params);
        } catch (IllegalAccessException e) {
            throw new ReflectionException(e);
        } catch (SecurityException e) {
            throw new ReflectionException(e);
        } catch (IllegalArgumentException e) {
            throw new ReflectionException(e);
        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof Exception) {
                throw new ReflectionException((Exception) e.getCause());
            } else {
                throw new ReflectionException(e);
            }

        }
    }

    /**
     * ??
     */
    public static List<Class<?>> withSupers(Class<?> c) {
        List<Class<?>> supers = new ArrayList<Class<?>>();
        supers.add(c);
        c = c.getSuperclass();
        while (c != null) {
            supers.add(c);
            c = c.getSuperclass();
        }
        return supers;
    }

    public FieldEx[] getDeclaredFields() {
        Field[] fields = cls.getDeclaredFields();
        FieldEx[] result = new FieldEx[fields.length];
        for (int i = 0; i < fields.length; i++) {
            result[i] = new FieldEx(fields[i], instanceClz == null ? this : instanceClz);
        }
        return result;
    }

    /**
     * Annotation
     */
    public <T extends Annotation> T getAnnotation(Class<T> t) {
        return cls.getAnnotation(t);
    }

    /**
     * ??
     * 
     * @param method
     * @return
     */
    public Type getMethodReturnType(Method method) {
        ClassEx cw = this;
        method = getRealMethod(method);
        if (method.getDeclaringClass() != this.cls) {
            Type type = GenericUtils.getSuperType(null, cls, method.getDeclaringClass());
            cw = new ClassEx(type);
        }
        return BeanUtils.getBoundType(method.getGenericReturnType(), cw);
    }

    /**
     * ??
     * 
     * @param method
     * @param index
     * @return
     */
    public Type getMethodParamType(Method method, int index) {
        ClassEx cw = this;
        method = getRealMethod(method);
        if (method.getDeclaringClass() != this.cls) {
            Type type = GenericUtils.getSuperType(null, cls, method.getDeclaringClass());
            cw = new ClassEx(type);
        }
        Type[] types = method.getGenericParameterTypes();
        if (index < 0 || index > types.length) {
            throw new IllegalArgumentException(StringUtils.concat("the method ", method.getName(), " has ",
                    String.valueOf(types.length), " params, index=", String.valueOf(index), " is out of bound."));
        }
        return BeanUtils.getBoundType(types[index], cw);
    }

    private Method getRealMethod(Method method) {
        Class<?> cls = method.getDeclaringClass();
        if (isCGLibProxy(cls)) {
            try {
                return cls.getSuperclass().getMethod(method.getName(), method.getParameterTypes());
            } catch (SecurityException e) {
                LogUtil.exception(e);
            } catch (NoSuchMethodException e) {
                LogUtil.exception(e);
            }
        }
        return method;
    }

    /**
     * ????
     * 
     * @param method
     * @return
     */
    public Type[] getMethodParamTypes(Method method) {
        ClassEx cw = this;
        method = getRealMethod(method);
        if (method.getDeclaringClass() != this.cls) {
            Type type = GenericUtils.getSuperType(null, cls, method.getDeclaringClass());
            cw = new ClassEx(type);
        }
        Type[] types = method.getGenericParameterTypes();
        for (int i = 0; i < types.length; i++) {
            types[i] = BeanUtils.getBoundType(types[i], cw);
        }
        return types;
    }

    /**
     * CGLib?class
     * 
     * @param clz
     * @return
     */
    public static Class<?> getRealClass(Class<?> clz) {
        if (isCGLibProxy(clz)) {
            return clz.getSuperclass();
        }
        return clz;
    }

    // ?CGLIB?
    private static boolean isCGLibProxy(Class<?> declaringClass) {
        return (declaringClass.getName().indexOf("$$EnhancerByCGLIB$$") > -1);
    }

    /**
     * ??
     * 
     * @param value
     * @param container
     * @param oldValue
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Object toProperType(Object value, ClassEx container, Object oldValue) {
        if (value == null)
            return null;
        Class<?> clz = value.getClass();
        if (container.isAssignableFrom(clz)) {
            if (container.isCollection()) {
                return checkAndConvertCollection((Collection) value, container);
            } else if (container.isMap()) {
                return checkAndConvertMap((Map) value, container);
            } else {
                return value;
            }
        } else if (CollectionUtil.isArrayOrCollection(clz)) {
            IterableAccessor<Object> accesor = new IterableAccessor<Object>(value);
            if (container.isArray()) {
                return BeanUtils.toProperArrayType(accesor, container, oldValue);
            } else if (container.isCollection()) {
                return BeanUtils.toProperCollectionType(accesor, container, oldValue);
            } else {
                BeanUtils.toProperType(accesor.toString(), container, oldValue);
            }
        }
        return BeanUtils.toProperType(ObjectUtils.toString(value), container, oldValue);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static Object checkAndConvertMap(Map rawValue, ClassEx container) {
        Entry<Type, Type> types = GenericUtils.getMapTypes(container.genericType);
        boolean checkKey = types.getKey() != Object.class;
        boolean checkValue = types.getValue() != Object.class;
        if (!checkKey && !checkValue)
            return rawValue;

        ClassEx tk = new ClassEx(types.getKey());
        ClassEx tv = new ClassEx(types.getValue());

        Set<Map.Entry> es = rawValue.entrySet();
        Map result;
        try {
            result = rawValue.getClass().newInstance();
        } catch (InstantiationException e1) {
            throw new IllegalArgumentException(e1);
        } catch (IllegalAccessException e1) {
            throw new IllegalArgumentException(e1);
        }
        for (Map.Entry e : es) {
            Object key = e.getKey();
            Object value = e.getValue();
            if (key != null && checkKey)
                key = toProperType(key, tk, null);
            if (value != null && checkValue)
                value = toProperType(value, tv, null);
            result.put(key, value);
        }
        return result;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static Object checkAndConvertCollection(Collection rawValue, ClassEx container) {
        Type type = GenericUtils.getCollectionType(container.genericType);
        if (type == Object.class)
            return rawValue;
        ClassEx t = new ClassEx(type);
        Collection result;
        try {
            result = rawValue.getClass().newInstance();
        } catch (InstantiationException e1) {
            throw new IllegalArgumentException(e1);
        } catch (IllegalAccessException e1) {
            throw new IllegalArgumentException(e1);
        }

        for (Object e : rawValue) {
            e = toProperType(e, t, null);
            result.add(e);
        }
        return result;
    }

    /**
     * class
     * 
     * @return
     */
    public String getName() {
        return cls.getName();
    }

    /**
     * class
     * 
     * @return
     */
    public String getSimpleName() {
        return cls.getSimpleName();
    }

    /**
     * ??
     * 
     * @return
     */
    public String getGenericName() {
        return genericType.toString();
    }

    /**
     * 
     * 
     * @param name
     * @param params
     * @return
     */
    public Method getPublicMethod(String name, Class<?>... params) {
        try {
            return cls.getMethod(name, params);
        } catch (SecurityException e) {
            throw new IllegalArgumentException(e.getMessage());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    /**
     * ?????????
     * 
     * @param name
     * @return
     */
    public MethodEx getMethodByName(String name) {
        MethodEx[] methods = BeanUtils.getMethodByName(this, name, 1, SearchMode.NOT_IN_SUPER_IF_FOUND);
        if (methods.length > 1) {
            throw new IllegalArgumentException(
                    "There are more than 1 method match the name " + name + " in class " + cls.getName());
        }
        if (methods.length == 0)
            return null;
        return methods[0];

    }

    /**
     * gettersetterfield
     * 
     * @return
     */
    public FieldEx[] getFieldsWithGetterAndSetter() {
        return BeanUtils.getFieldsWithGetterAndSetter(this.cls, Object.class);
    }

    public FieldEx[] getFieldsWithGetter() {
        return BeanUtils.getFieldsWithGetter(this.cls, Object.class);
    }

    public FieldEx[] getFieldsWithSetter() {
        return BeanUtils.getFieldsWithSetter(this.cls, Object.class);
    }

    /**
     * field??
     * 
     * @return
     */
    public String[] getFieldNames() {
        return BeanUtils.getFieldNames(this.cls, Object.class);
    }

    /**
     * Field
     * 
     * @return
     */
    public FieldEx[] getFields() {
        return BeanUtils.getFields(this.cls, Object.class, false, false);
    }

    /**
     * public
     * 
     * @return
     */
    public MethodEx[] getMethods() {
        return BeanUtils.getMethods(this.cls);
    }

    /**
     * 
     * 
     * @param name
     * @return
     */
    public Class<?> getFieldType(String name) {
        return BeanUtils.getFieldType(cls, name);
    }

    /**
     * ??
     * 
     * @param name
     * @return
     */
    public Type getFieldGenericType(String name) {
        return BeanUtils.getField(this, name).getGenericType();
    }

    /**
     * ??
     * 
     * @param name
     * @return
     */
    public Type getFieldGenericType(Field field) {
        Assert.notNull(field);
        ClassEx cw = this;
        if (field.getDeclaringClass() != this.cls) {
            Type type = GenericUtils.getSuperType(null, cls, field.getDeclaringClass());
            cw = new ClassEx(type);
        }
        return BeanUtils.getBoundType(field.getGenericType(), cw);
    }

    /**
     * ?
     * 
     * @param className
     * @param loder
     * @return
     * @throws ReflectionException
     */
    public static final ClassEx getClassEx(String className, ClassLoader loder) throws ReflectionException {
        try {
            if (loder == null)
                loder = ClassEx.class.getClassLoader();
            Class<?> c = loder.loadClass(className);
            return new ClassEx(c);
        } catch (ClassNotFoundException e) {
            throw new ReflectionException(e, "Class: " + className + " not found.");
        }
    }

    /**
     * 
     * 
     * @param className
     * @return
     * @throws ReflectionException
     */
    public static final ClassEx getClassEx(String className) throws ReflectionException {
        return getClassEx(className, null);
    }

    /**
     * ????????
     * 
     * @param name
     * @return
     */
    public MethodEx getFirstMethodByName(String name) {
        MethodEx[] methods = BeanUtils.getMethodByName(this, name, 1, SearchMode.NOT_IN_SUPER_IF_FOUND);
        if (methods.length > 0)
            return methods[0];
        return null;
    }

    /*
     * ???? <p>Title: getImplType</p> <p>Description: </p>
     * 
     * @param declaration
     * 
     * @return
     * 
     * @see
     * jef.tools.reflect.GenericProvider#getImplType(java.lang.reflect.TypeVariable
     * )
     */
    public Type getImplType(TypeVariable<?> declaration) {
        if (declaration.getGenericDeclaration() == this.cls && this.genericType instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) genericType;
            int n = 0;
            for (TypeVariable<?> tv : cls.getTypeParameters()) {
                if (tv == declaration)
                    break;
                n++;
            }
            return pType.getActualTypeArguments()[n];
        }
        return null;
    }

    public FieldEx getField(String field) {
        return BeanUtils.getField(this, field);
    }

    public MethodEx getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
        return new MethodEx(cls.getMethod(name, parameterTypes), this);
    }

    public MethodEx getMethodIfExist(String name, Class<?>... paramTypes) {
        try {
            Method method = cls.getMethod(name, paramTypes);
            return new MethodEx(method, this);
        } catch (SecurityException e) {
            LogUtil.exception(e);
        } catch (NoSuchMethodException e) {
            LogUtil.exception(e);
        }
        return null;
    }

    public boolean isInterface() {
        return cls.isInterface();
    }

    public Class<?> getEnclosingClass() {
        return cls.getEnclosingClass();
    }

    public int getModifiers() {
        return cls.getModifiers();
    }

    public Object[] getEnumConstants() {
        return cls.getEnumConstants();
    }

    public MethodEx getDeclaredMethod(String name, Class<?>... parameterTypes)
            throws SecurityException, NoSuchMethodException {
        Method m = cls.getDeclaredMethod(name, parameterTypes);
        return new MethodEx(m, instanceClz == null ? this : instanceClz);
    }

    /**
     * ??
     * 
     * @return
     */
    public ClassEx getSuperclass() {
        Type s = cls.getGenericSuperclass();
        if (s == null)
            return null;
        ClassEx result = new ClassEx(s);
        if (instanceClz != null) {
            result.instanceClz = instanceClz;
        } else {
            result.instanceClz = this;
        }
        if (Throwable.class == result.getWrappered()) {
            return null;
        }
        return result;
    }

    public MethodEx[] getDeclaredMethods() {
        Method[] methods = cls.getDeclaredMethods();
        MethodEx[] result = new MethodEx[methods.length];
        for (int i = 0; i < methods.length; i++) {
            result[i] = new MethodEx(methods[i], instanceClz == null ? this : instanceClz);
        }
        return result;
    }

    public FieldEx getDeclaredField(String name) throws SecurityException, NoSuchFieldException {
        return new FieldEx(cls.getDeclaredField(name), instanceClz == null ? this : instanceClz);
    }

    public Constructor<?> getDeclaredConstructor(Class<?>... params)
            throws SecurityException, NoSuchMethodException {
        return cls.getDeclaredConstructor(params);
    }

    @Override
    public int hashCode() {
        return genericType.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof ClassEx) {
            return this.genericType.equals(((ClassEx) obj).genericType);
        }
        return false;
    }

    public Package getPackage() {
        return cls.getPackage();
    }

    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return cls.isAnnotationPresent(annotationClass);
    }

    @Override
    public String toString() {
        return genericType.toString();
    }

    public InputStream getResourceAsStream(String string) {
        return cls.getResourceAsStream(string);
    }

    public ClassLoader getClassLoader() {
        return cls.getClassLoader();
    }

    public String getPackageName() {
        String s = cls.getName();
        int n = s.lastIndexOf('.');
        if (n > -1) {
            return s.substring(0, n);
        } else {
            return "";
        }
    }

    /**
     * ??class?Wrapper
     * 
     * @param name
     * @return class??null
     */
    public static ClassEx forName(String name) {
        Class<?> c = getClass(name);
        return c == null ? null : new ClassEx(c);
    }

    /**
     * ??class,null
     * 
     * @param name
     * @return
     */
    public static Class<?> getClass(String name) {
        try {
            return Class.forName(name);
        } catch (ClassNotFoundException e) {
            System.err.println("Class:" + name + " not found!");
            return null;
        }
    }

    public boolean isAssignableFrom(Class<?> class1) {
        return cls.isAssignableFrom(class1);
    }

    public boolean isGeneric() {
        return !this.genericType.equals(cls);
    }

    public boolean isEnum() {
        return cls.isEnum();
    }

    public boolean isArray() {
        return GenericUtils.isArray(genericType);
    }

    public boolean isCollection() {
        return CollectionUtil.isCollection(genericType);
    }

    public boolean isMap() {
        return Map.class.isAssignableFrom(cls);
    }

    public Type getComponentType() {
        return CollectionUtil.getComponentType(genericType);
    }

    /**
     * ?
     * 
     * @return
     */
    public Class<?>[] getInterfaces() {
        return cls.getInterfaces();
    }

    /**
     * ?????
     * 
     * @return
     */
    public Class<?>[] getAllInterfaces() {
        LinkedHashSet<Class<?>> intf = new LinkedHashSet<Class<?>>();
        Class<?> c = cls;
        while (c != Object.class) {
            for (Class<?> ic : c.getInterfaces()) {
                intf.add(ic);
            }
            c = c.getSuperclass();
        }
        return intf.toArray(new Class<?>[intf.size()]);
    }
}