java 泛型问题

问题描述

获取类型泛型中的原始类型

问题出现的环境背景及自己尝试过哪些方法

image.png

要在这里获取原始类型

 @Data
    public static class CustomInput {
        private BaseInput<Example> exampleBaseInput;
    }

    @Data
    public static class BaseInput<T> {
        private T data;
    }
    @Data
    public static class Example{
        protected List<String> list = new ArrayList<>();
        protected List<Integer> list2 = new ArrayList<>();
        protected Set<String> set = new HashSet<>();
        protected Set<Integer> set2 = new HashSet<>();
        protected Map<String,String> map = new HashMap<>();
        protected Map<String,Integer> map2 = new HashMap<>();
    }

上面的类型中, 给了 CustomInput.class , 要动态拿到 Example 的 class 对象

相关代码

粘贴代码文本(请勿用截图)

package com.sanri.tools.modules.core.service.data;

import com.sanri.tools.modules.core.utils.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 随机数据生成
 */
@Slf4j
@Component
public class RandomDataService {
    /**
     * 给一个类型注入数据,在指定的类加载器中去查找类
     * @param className
     * @param classLoader
     * @return
     * @throws ClassNotFoundException
     */
    public Object randomData(String className,ClassLoader classLoader) throws ClassNotFoundException {
        Class<?> clazz = classLoader.loadClass(className);
        return populateData(clazz);
    }

    /**
     * 给一个类型注入数据
     * @param clazz
     * @return
     */
    public Object populateData(Class<?> clazz){
        if(isPrimitiveExtend(clazz)){
            return populateDataOrigin(null,clazz);
        }
        return populateDataComplex(clazz);
    }

    /**
     * 这个方法可以注入简单类型和复杂类型,注入单个类型
     * @param type
     * @param columnName
     * @return
     */
    private Object populateData(Type type,String columnName){
        if(type instanceof Class){
            Class propertyType = (Class) type;
            if (isPrimitiveExtend(propertyType)){
                return populateDataOrigin(columnName,propertyType);
            }
            return populateDataComplex(propertyType);
        }
        // 接下来这些都是 ParameterizedType
        if(type instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType) type;
            // rawType 认为一定是 class ,其实还是有风险的,先这样吧
            Class propertyType = (Class) parameterizedType.getRawType();
            if(propertyType == List.class || propertyType == Set.class){
                return populateCollectionData(parameterizedType, columnName);
            }
            if(propertyType == Map.class){
                return populateMapData(parameterizedType, columnName);
            }

            // 自定义的 ParameterizedType 类型 TypeVariableImpl
            final PropertyDescriptor[] beanSetters = ReflectUtils.getBeanSetters(propertyType);
            for (PropertyDescriptor beanSetter : beanSetters) {
                final Method writeMethod = beanSetter.getWriteMethod();
                final Type[] genericParameterTypes = writeMethod.getGenericParameterTypes();
                if (genericParameterTypes != null){
                    final Type genericParameterType = genericParameterTypes[0];
                    // TODO 请把你的实现思路写在这里
                    System.out.println(genericParameterType);
                }
            }

        }

        log.error("不支持的类型:[{}]",type);
        return null;
    }

    /**
     * 注入 map 数据
     * @param writeMethod
     * @param columnName
     * @return
     */
    private Map populateMapData(ParameterizedType parameterType, String columnName){
        Map map = new HashMap();

        Class keyTypeArgument = (Class) parameterType.getActualTypeArguments()[0];
        Class valueTypeArgument = (Class) parameterType.getActualTypeArguments()[1];

        // 随机创建 2~ 10 个键值对
        int count = RandomUtils.nextInt(2, 10);

        for (int i = 0; i < count; i++) {
            Object key = populateData(keyTypeArgument, columnName);
            Object value = populateData(valueTypeArgument, columnName);
            map.put(key,value);
        }
        return map;
    }

    /**
     * 注入复杂对象值,只能注入复杂类型 ; 这个是真正的主入口,注入一个复杂类型对象数据
     * @param clazz
     * @return
     */
    private Object populateDataComplex(Class<?> clazz) {
        Object object = ReflectUtils.newInstance(clazz);

        PropertyDescriptor[] beanSetters = ReflectUtils.getBeanSetters(clazz);
        for (PropertyDescriptor beanSetter : beanSetters) {
            Method writeMethod = beanSetter.getWriteMethod();
            String columnName = beanSetter.getName();
            Type genericParameterType = writeMethod.getGenericParameterTypes()[0];
            Object populateData = populateData(genericParameterType, columnName);

            ReflectionUtils.invokeMethod(writeMethod, object, populateData);
        }
        return object;
    }

    /**
     * 对于 set , list  等 注入数据
     * @param writeMethod
     * @param list
     * @param columnName
     * @return
     */
    private Collection populateCollectionData(ParameterizedType genericParameterType, String columnName) {
        Collection collection = null;
        Class rawType = (Class) genericParameterType.getRawType();
        if(rawType == List.class){
            collection = new ArrayList();
        }else if(rawType == Set.class){
            collection = new HashSet();
        }

        Class typeArgument = (Class) genericParameterType.getActualTypeArguments()[0];
        // 每个 List 创建 随机 2 ~ 10 条数据
        int count = RandomUtils.nextInt(2, 10);
        for (int i = 0; i < count; i++) {
            Object populateData = populateData(typeArgument, columnName);
            collection.add(populateData);
        }

        return collection;
    }

    /**
     * 对某一列注入原始类型的数据
     * @param columnName
     * @param propertyType
     * @return
     */
    protected Object populateDataOrigin( String columnName, Class<?> propertyType) {
        columnName = Objects.toString(columnName,"");

        if(propertyType == String.class){
            int randomLength = RandomUtils.nextInt(5,20);
            String value = RandomStringUtils.randomAlphabetic(randomLength);
           
            return value;
        }
        if(propertyType == Date.class){
            return RandomUtil.date();
        }
        if(propertyType == BigDecimal.class){
            BigDecimal bigDecimal = new BigDecimal(RandomUtils.nextDouble(100,2000000));
            bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
            return bigDecimal;
        }
        if (propertyType == Integer.class || propertyType == int.class){
            Integer num = RandomUtils.nextInt(10,1000);
            if(columnName.toLowerCase().contains("age")) {
                num = RandomUtils.nextInt(20,150);
            }
            return num;
        }
        if(propertyType == Long.class ||  propertyType == long.class){
            return RandomUtils.nextLong(10,10000000);
        }
        if(propertyType == Float.class || propertyType == float.class){
            return RandomUtils.nextFloat(10,1000);
        }
        if(propertyType == Double.class || propertyType == double.class){
            return RandomUtils.nextDouble(10,1000);
        }
        if(propertyType == Boolean.class || propertyType == boolean.class){
//            return RandomUtils.nextInt(1,1000) & 2 ;
            return RandomUtils.nextBoolean();
        }
        if(propertyType == Short.class || propertyType == short.class){
            int nexInt = RandomUtils.nextInt(129, 500);
            return new Integer(nexInt).shortValue();
        }
        if(propertyType == Character.class || propertyType == char.class){
            return RandomStringUtils.randomAlphanumeric(1).charAt(0);
        }
        if(propertyType == Byte.class || propertyType == byte.class){
            return RandomUtils.nextBytes(1)[0];
        }

        // 数组只能支持一维数组,不要使用二维数组
        if(propertyType.isArray()){
            Class<?> componentType = propertyType.getComponentType();
            int count = RandomUtils.nextInt(2, 10);
            Object arr = Array.newInstance(componentType, count);

            for (int i = 0; i < count; i++) {
                Object value = populateData(componentType);
                Array.set(arr,i,value);
            }
            return arr;
        }

        log.error("无法处理的类型[{}]",propertyType);
        return null;
    }


    /**
     * 判断是否是原始型扩展
     * 包含 原始型及包装类,String,Date,BigDecimal,Array 数组也当原始型处理,因为数组类型必须要匹配,不能自动拆箱装箱
     * @param propertyType
     * @return
     */
    private boolean isPrimitiveExtend(Class<?> propertyType) {
        return ClassUtils.isPrimitiveOrWrapper(propertyType) || propertyType == String.class || propertyType == Date.class || propertyType == BigDecimal.class || propertyType.isArray();
    }
}

你期待的结果是什么?实际看到的错误信息又是什么?

阅读 1.5k
1 个回答
public class ProxyTest {

    interface Apple {

        void message();

    }

    static class Type<T> {
        private T t;
    }


    Type<Apple> type;

    @Test
    public void doTest() throws Exception {
        final Class<ProxyTest> proxyTestClass = ProxyTest.class;
        final Field typeField = proxyTestClass.getDeclaredField("type");

        typeField.setAccessible(true);
        final AnnotatedParameterizedType annotatedType = (AnnotatedParameterizedType) typeField.getAnnotatedType();
        System.out.println(/* 拿到范型的数组 */annotatedType.getAnnotatedActualTypeArguments()[0].getType());
    }

}

运行结果

interface org.example.ProxyTest$Apple // 这是个class对象

这是代码例子

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏