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

com.github.azbh111.utils.java.reflect.GenericUtils Maven / Gradle / Ivy

The newest version!
package com.github.azbh111.utils.java.reflect;

import com.github.azbh111.utils.java.reflect.model.MuttableGenericArrayType;
import com.github.azbh111.utils.java.reflect.model.MuttableParameterizedType;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

/**
 *
 * @author pyz
 * @date 2019/4/15 10:59 PM
 */
public class GenericUtils {

    /**
     * 方法Class.getGenericSuperclass()只能获取父类的
     * 本方法支持多层extends/implements
     *
     * 例: com.github.azbh111.utils.java.reflect.generic.GenericUtilsTest.getGenericSuperclass()
     *
     * @param from
     * @param to
     * @return
     */
    public static ParameterizedType getGenericSuperclass(Class from, Class to) {
        return resolve(from, new LinkedList(), 0, to);
    }

    /**
     * 方法Class.getGenericSuperclass()只能获取父类的
     * 本方法支持多层extends/implements
     *
     * 例: com.github.azbh111.utils.java.reflect.generic.GenericUtilsTest.getGenericSuperclass()
     *
     * @param from
     * @param to
     * @return
     */
    public static ParameterizedType getGenericSuperclass(ParameterizedType from, Class to) {
        LinkedList nodes = new LinkedList();
        GenericNode node = new GenericNode();
        node.setSource(from);
        node.setBridges(((Class) from.getRawType()).getTypeParameters());
        nodes.add(node);
        return resolve((Class) from.getRawType(), nodes, 0, to);
    }

    public static Type replaceTypeVariable(Type target, String name, Type type) {
        Type r = target;
        if (target instanceof TypeVariable) {
            TypeVariable tv = (TypeVariable) target;
            if (tv.getName().equals(name)) {
                r = type;
            }
        } else if (target instanceof ParameterizedType) {
            MuttableParameterizedType mpt;
            if (target instanceof MuttableParameterizedType) {
                mpt = (MuttableParameterizedType) target;
            } else {
                mpt = MuttableParameterizedType.of((ParameterizedType) target);
            }
            Type[] ts = mpt.getActualTypeArguments();
            for (int i = 0; i < ts.length; i++) {
                ts[i] = replaceTypeVariable(ts[i], name, type);
            }
            r = mpt;
        } else if (target instanceof GenericArrayType) {
            MuttableGenericArrayType mgat;
            if (target instanceof MuttableGenericArrayType) {
                mgat = (MuttableGenericArrayType) target;
            } else {
                mgat = MuttableGenericArrayType.of((GenericArrayType) target);
            }
            mgat.setGenericComponentType(replaceTypeVariable(mgat.getGenericComponentType(), name, type));
            r = mgat;
        }
        return r;
    }

    private static ParameterizedType resolve(Class from, LinkedList stacks, int skip, Class to) {
        if (from == to) {
            return resolve(stacks, skip, to);
        }
        Class sc = from.getSuperclass();
        Type gsc = from.getGenericSuperclass();
        Class[] itfs = from.getInterfaces();
        Type[] gitfs = from.getGenericInterfaces();
        int size = itfs.length;
        for (int i = -1; i < size; i++) {
            Class superClass = i == -1 ? sc : itfs[i];
            Type genericSuperClass = i == -1 ? gsc : gitfs[i];
            if (superClass == null || genericSuperClass == null) {
                continue;
            }
            if (to.isAssignableFrom(superClass)) {
                TypeVariable[] tps = superClass.getTypeParameters();
                if (tps == null || tps.length == 0 || !(genericSuperClass instanceof ParameterizedType)) {
                    ParameterizedType pt = resolve(superClass, stacks, stacks.size(), to);
                    if (pt != null) {
                        return pt;
                    }
                } else {
                    GenericNode node = new GenericNode();
                    node.setSource((ParameterizedType) genericSuperClass);
                    node.setBridges(tps);
                    stacks.add(node);
                    ParameterizedType pt = resolve(superClass, stacks, 0, to);
                    if (pt != null) {
                        return pt;
                    }
                }
            }
        }
        return null;
    }

    private static ParameterizedType resolve(LinkedList stacks, int skip, Class to) {
        MuttableParameterizedType target = new MuttableParameterizedType();
        target.setRawType(to);
        target.setActualTypeArguments(new Type[to.getTypeParameters().length]);
        System.arraycopy(to.getTypeParameters(), 0, target.getActualTypeArguments(), 0, target.getActualTypeArguments().length);
        resolve(stacks, skip, target);
        return target;
    }

    private static void resolve(List nodes, int skip, MuttableParameterizedType target) {
        ListIterator it = nodes.listIterator(nodes.size() - skip);
        while (it.hasPrevious()) {
            resolve(it.previous(), target);
        }
    }

    private static void resolve(GenericNode node, MuttableParameterizedType target) {
        TypeVariable[] bridges = node.getBridges();
        Type[] sources = node.getSource().getActualTypeArguments();
        for (int i = 0; i < node.getBridges().length; i++) {
            replaceTypeVariable(target, bridges[i].getName(), sources[i]);
        }
    }

    private static class GenericNode {
        ParameterizedType source;
        TypeVariable[] bridges;

        public ParameterizedType getSource() {
            return source;
        }

        public void setSource(ParameterizedType source) {
            this.source = source;
        }

        public TypeVariable[] getBridges() {
            return bridges;
        }

        public void setBridges(TypeVariable[] bridges) {
            this.bridges = bridges;
        }

        public void setBridges(Type[] actualTypeArguments) {

        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy