Java内省

Introspector

Java JDK Introspector

在开发框架的时候经常会用到Java类的 get/set方法设置或者获取值,但是每次都是用反射来完成此类操作或与麻烦,JDK提供了 一套API,专门操作Java对象的属性。内省专门操作Java对象的属性。

在Java中private int id 这种叫做字段field,而get/set方法才被叫做属性property

Java中的属性是指设置和读取字段的方法。
属性名称就是去掉get/set后面的部分

package cn.pickle.entity;

import lombok.Data;

/**
 * @author Pickle
 * @version V1.0
 * @date13:53 2022/12/14
 */
@Data	//该注解自动生成 get/set 方法
public class Student {
    private Long id;	//field 字段
    private String password;	//field 字段
    private Integer classNumber;//field 字段
    
    
    public String getTest(){
    return "TEST";
}

测试函数

package cn.pickle.introspector;

import cn.pickle.entity.Student;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
public class demo {
    public static void main(String[] args) throws IntrospectionException {
        //获得Student属性封装到beanInfo中
        final BeanInfo beanInfo = Introspector.getBeanInfo(Student.class);

        //得到类中的所有属性描述器
        final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

        System.out.println("属性的个数为" + propertyDescriptors.length);

        for (PropertyDescriptor pd :
                propertyDescriptors) {
            System.out.println("属性" + pd.getName());
        }
    }
}

结果

image-20221216142346813

属性test可以看出获得的属性和字段并没有关系,而属性class则是父类的getClass()方法

PropertyDescriptor

propertyDescriptor通过反射快速操作JavaBean的getter/setter方法。

PropertyDescriptor获取get/set方法的API

image-20221216142901158

实例

package cn.pickle.introspector;

import cn.pickle.entity.Student;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
public class demo {
    public static void main(String[] args) {
        try {
            //获取描述Student的Class实例
            final Class<?> stuClass = Class.forName("cn.pickle.entity.Student");

            final Student student = (Student)stuClass.newInstance();

            //获取id的属性描述器
            final PropertyDescriptor pd = new PropertyDescriptor("id", Student.class);
            
            //setId()
            final Method writeId = pd.getWriteMethod();

            //getId()
            final Method readId = pd.getReadMethod();

            System.out.println(student.toString());

            writeId.invoke(student,1L);

            System.out.println(student.toString());

            System.out.println("利用属性描述器获取的get方法读取id的值为:" + readId.invoke(student,null));

        }catch (Exception error){
            System.out.println("没有找到该类" + error.getMessage());
        }
    }
}

输出

image-20221216145024057

Apache BeanUtils

更高效的内省框架

       <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>

简单使用

package cn.pickle.introspector;

import cn.pickle.entity.Student;
import org.apache.commons.beanutils.BeanUtils;

import java.beans.*;
import java.lang.reflect.InvocationTargetException;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
public class demo {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Student student = new Student();
        final String id = BeanUtils.getProperty(student, "id");
        System.out.println("BeanUtils 获取的 id 为: " + id);

        BeanUtils.setProperty(student,"id",1L);
        System.out.println("BeanUtils 设置后的Student" + student.toString());
    }
}

输出

image-20221216150221257

ConvertUtils

实现非基本类型的自定义转换封装

将Map属性批量封装到Bean中

package cn.pickle.introspector;

import cn.pickle.entity.Student;
import org.apache.commons.beanutils.BeanUtils;

import java.beans.*;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
public class demo {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Student student = new Student();
        Map<String,String> map = new HashMap<>();
        map.put("id","1");
        map.put("classNumber","1");
        map.put("password","1");
        BeanUtils.populate(student,map);
        System.out.println(student);
    }
}

输出

image-20221216151316562

但是如果里面包含不是基本类型,我们在原来的基础上给Student加上一个Date字段

image-20221216151414430

package cn.pickle.introspector;

import cn.pickle.entity.Student;
import org.apache.commons.beanutils.BeanUtils;

import java.beans.*;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
public class demo {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Student student = new Student();
        Map<String,String> map = new HashMap<>();
        map.put("id","1");
        map.put("classNumber","1");
        map.put("password","1");
        map.put("birthday","2001-01-01");
        BeanUtils.populate(student,map);
        System.out.println(student);
    }
}

直接报错

image-20221216151551286

意思就是DateConverter不支持默认的String到Date转换,有两种解决方案。

  • 自定义转换器然后用ConvertUtils注册。
package cn.pickle.introspector;

import cn.pickle.entity.Student;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;

import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
@SuppressWarnings("unchecked")
public class demo {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Student student = new Student();
        Map<String,String> map = new HashMap<>();
        map.put("id","1");
        map.put("classNumber","1");
        map.put("password","1");
        map.put("birthday","2001-01-01");

        ConvertUtils.register(new Converter() {
            /**
             * @param <T>
             * @param aClass 目标类型
             * @param o      当前传入的值
             * @return
             */
            @Override
            public <T> T convert(Class<T> aClass, Object o) {
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                if(o instanceof String){// String -> Date
                    String date = (String) o;
                    try {
                        final Date parse = df.parse(date);
                        return (T) parse;
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }else{//Date -> String
                    final String format = df.format((Date) o);
                    return (T) format;
                }
                return null;
            }
        }, Date.class);

        BeanUtils.populate(student,map);
        System.out.println(student);
    }
}

结果

image-20221216154348750

  • 使用提供的转换器
package cn.pickle.introspector;

import cn.pickle.entity.Student;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;

import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Pickle
 * @version V1.0
 * @date 2022/12/16 14:11
 */
@SuppressWarnings("unchecked")
public class demo {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Student student = new Student();
        Map<String,String> map = new HashMap<>();
        map.put("id","1");
        map.put("classNumber","1");
        map.put("password","1");
        map.put("birthday","2001-01-01");

//        ConvertUtils.register(new Converter() {
//            /**
//             * @param <T>
//             * @param aClass 目标类型
//             * @param o      当前传入的值
//             * @return
//             */
//            @Override
//            public <T> T convert(Class<T> aClass, Object o) {
//                DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
//                if(o instanceof String){// String -> Date
//                    String date = (String) o;
//                    try {
//                        final Date parse = df.parse(date);
//                        return (T) parse;
//                    } catch (ParseException e) {
//                        e.printStackTrace();
//                    }
//                }else{//Date -> String
//                    final String format = df.format((Date) o);
//                    return (T) format;
//                }
//                return null;
//            }
//        }, Date.class);
        ConvertUtils.register(new DateLocaleConverter(),Date.class);
        BeanUtils.populate(student,map);
        System.out.println(student);
    }
}

image-20221216154534508

posted @ 2022-12-16 15:46  破忒头头  阅读(141)  评论(0)    收藏  举报