Java foundation of introspection

Java foundation of introspection

What is introspection

  First of all, we need to know what is introspection. That is, according to my own understanding is encapsulated in principle reflected more convenient to operate JavaBean

JavaBean is special format class specification which:

  1. JavaBean class must be a public class, using keywords public statement class.
  2. JavaBean class must be declared as a public no-argument constructor.
  3. JavaBean class instance variables must be private, that is, all instance variables are declared using the keyword private.
  4. We must provide a public getter / setter methods for the JavaBean class instance variables. (In getter / setter methods, you can do some access control, data validation, etc., in order to ensure data security, legitimacy.)
  5. JavaBean class instance attribute naming rules:

    1. Before the property name two letters are lowercase: The first letter capitalized property name, then used as getter / setter methods get the part / set, such as the property named name, it's getter / setter methods for the getName / setName.
    2. The second uppercase letter attribute name: attribute name used directly as getter / setter methods get / set the rear portion, i.e., the same attribute name case. As a property named uName, its getter / setter methods to getuName / setuName.
    3. Before the property name two capital letters: attribute name directly used as getter / setter methods get / set rear part, that same attribute name case. As a property named IDcode, its getter / setter methods to getIDcode / setIDcode.
    4. Property name capitalized: The property name used directly as get / set rear portion of the getter / setter methods, that same attribute name case. As a property named Ucode, its getter / setter methods to getUcode / setUcode. But this case, the error in the application can not find the property occurs .

Reference article

How to use introspection

Introspective main classes (interfaces) are: Introspector(s), BeanInfo(Interface), PropertyDescriptor(s), which are three in java.bean package.

IntrospectorIntrospective entrance, is a utility class used to obtain BeanInfoinformation that is of a JavaBean.


Test Bean: Student

public class Student {
    private String name;
    private String address;

    public Student() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
//static BeanInfo getBeanInfo(Class<?> beanClass):在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件
BeanInfo beanInfo = Introspector.getBeanInfo(Student.class);

After obtaining a message to the bean you can get all of the attributes of the descriptor:

PropertyDescriptor[] p = beanInfo.getPropertyDescriptors();

Traversing print it and see the results:

BeanInfo beanInfo = Introspector.getBeanInfo(Student.class);
PropertyDescriptor[] p = beanInfo.getPropertyDescriptors();
System.out.println(p.length);
for (PropertyDescriptor descriptor : p) {
    System.out.println(descriptor);
}

//输出--------------
p.length = 3
java.beans.PropertyDescriptor[name=address; propertyType=class java.lang.String; readMethod=public java.lang.String nei_xing.Student.getAddress(); writeMethod=public void nei_xing.Student.setAddress(java.lang.String)]
//为了方便观察加了注释隔开
java.beans.PropertyDescriptor[name=class; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()]
//
java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; readMethod=public java.lang.String nei_xing.Student.getName(); writeMethod=public void nei_xing.Student.setName(java.lang.String)]

Here, Student properties but only two but three Object descriptor, because:

Object declares getClass () method to get an object of type Class object itself, since all classes inherit from Object, so all classes have getClass () method. But not class class field (keyword class, the class name not), but not the setClass () method, so when using introspection generally need to filter out programming "class" attributes
Reference

Solution:
Use getBeanInfo(Class<?> beanClass)overloaded methods:
static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass): breakpoint given class, which is obtained BeanInfo
example:

BeanInfo beanInfo1 = Introspector.getBeanInfo(Student.class, Object.class);

In this case the descriptor whose properties can only get two Student, and filtered out classproperties.

After obtaining each attribute descriptor can get and set its Getter / Setter Method of:

Student stu = new Student();
BeanInfo beanInfo1 = Introspector.getBeanInfo(Student.class, Object.class);
PropertyDescriptor[] p1 = beanInfo1.getPropertyDescriptors();
System.out.println(p1.length);
for (PropertyDescriptor d : p1) {
    String name = d.getName();
    System.out.println("name = " + name);
    Method getter = d.getReadMethod();//获取getter方法
    Method setter = d.getWriteMethod();//获取setter方法
    if ("name".equals(name)){
        setter.invoke(stu, "张三");//使用反射调用该方法
    }
    if ("address".equals(name)){
        setter.invoke(stu, "上海");
    }
    System.out.println(getter.invoke(stu));
}

Output:

2
name = address
上海
name = name
张三

The above is an introspective implementation, the get property descriptors except BeanInfo object can also be created directly Attribute Description:

PropertyDescriptor pd = new PropertyDescriptor("address", Student.class);
Method getter = pd.getReadMethod();
Method setter = pd.getWriteMethod();

Put two Servlet in introspection Demo:


Demo1

Front page:

<form action="/introspectorServlet" method="post">
    姓名 <input type="text" name="name" /> <br/>
    住址 <input type="text" name="address"/> <br/>
    <input type="submit" value="提交"/>
</form>

IntrospectorServlet:

@WebServlet("/introspectorServlet")
public class IntrospectorServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //处理请求乱码
        request.setCharacterEncoding("UTF-8");
        //获取页面提交的所有的数据
        /*
            map集合的key是form表单标签的name属性值
            map集合的value是浏览器输入框输入的值,以String类型的数组形式接收
            举例:
            住址 <input type="text" name="address"/> <br/>
            key:address
            value:{"上海"}
         */
        Map<String, String[]> m = request.getParameterMap();
//        System.out.println(m);
        //创建封装属性的目标对象person
        Person p = new Person();
        try {
            //调用方法
            setProperty(p,m);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(p.getName());
        System.out.println(p.getAddress());
    }

    private void setProperty(Object obj, Map<String, String[]> m) throws Exception {
        // 将请求参数中 map的key 与传入对象属性名称 比较,如果一致,将参数的值赋值给对象属性
        //使用内省类获取BeanInfo类的对象
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        //获取所有的属性描述器
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        //遍历数组取出每一个属性描述器
        for (PropertyDescriptor descriptor : propertyDescriptors) {
            //获取Person类中的属性
            String property_name = descriptor.getName();
            //判断属性在map中是否存在对应值
            if(m.containsKey(property_name)){
                //包含
                //获取对应的value值
                String value = m.get(property_name)[0];
                /*
                     Method getWriteMethod() 获得应该用于写入属性值的方法。
                 */
                Method setter = descriptor.getWriteMethod();
                //将value 写到属性中
                setter.invoke(obj, value);
            }
        }
    }
}

Using request.getParameterMap();data obtained from the front desk are strings, then how to use technology to encapsulate the data to introspection on the basic types of javabean in the field?


Demo1

Student Bean class

public class Person {
    private String name;
    private String address;
    private int age;
    private double money;


    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", age=" + age +
                ", money=" + money +
                '}';
    }
}

Servlet Code:

@WebServlet("/introspector2Servlet")
public class IntrospectorServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //处理中文乱码
        request.setCharacterEncoding("UTF-8");
        Person p = new Person();
        //获取所有的数据
        //key 标签 name属性值  value 输入的值
        Map<String, String[]> map = request.getParameterMap();
        try {
            setProperty(p, map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(p.getName());
        System.out.println(p.getAddress());
        System.out.println(p.getAge());
        System.out.println(p.getMoney());
    }

    private void setProperty(Object obj, Map<String, String[]> map) throws Exception {
        //内省
        //获取所有的属性封装到BeanInfo对象中
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        //获取所有的属性描述器
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        //遍历
        for (PropertyDescriptor descriptor : propertyDescriptors) {
            //获取属性名
            String propertyName = descriptor.getName();
            //判断集合中是否包含当前属性名
            if (map.containsKey(propertyName)) {
                //包含
                //获取get方法
                Method getterMethod = descriptor.getReadMethod();
                //获取get方法返回值类型 String int double
                String returnTypeName = getterMethod.getReturnType().getSimpleName();

                //获取set方法
                Method setterMethod = descriptor.getWriteMethod();
                //获取mapvalue
                String value = map.get(propertyName)[0];//"18"
                //多分支语句
                switch (returnTypeName) {
                    case "int":
                        int age = Integer.parseInt(value);
                        //执行set方法
                        setterMethod.invoke(obj, age);
                        break;
                    case "double":
                        double v = Double.parseDouble(value);
                        //执行set方法
                        setterMethod.invoke(obj, v);
                        break;
                    case "float":
                        float v1 = Float.parseFloat(value);
                        //执行set方法
                        setterMethod.invoke(obj, v1);
                        break;
                    case "long":
                        long v2 = Long.parseLong(value);
                        //执行set方法
                        setterMethod.invoke(obj, v2);
                        break;
                    case "boolean":
                        boolean v3 = Boolean.parseBoolean(value);
                        //执行set方法
                        setterMethod.invoke(obj, v3);
                        break;
                    default:
                        //执行set方法
                        setterMethod.invoke(obj, value);
                        break;
                }
            }
        }
    }
}

BeanUtils Tools

You can see directly introspection there are some complicated, so most of the time you can use the apache tools: org.apache.commons.beanutils.BeanUtils, (using the need to import commons-beanutils-1.9.2.jarand commons-logging-1.1.1.jartwo packages) , this is a maven coordinates:

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

This tool class has a populate () method: static populate(Object bean, Map<String,String[]> properties), the Map of the key that is a String to and attribute names JavaBean is consistent in order to complete the package (or and name Getter / Setter methods are related, at least the Spring JdbcTemplate is such , modify the property name but does not modify Getter / Setter method can still complete the package)

Then encapsulation can be completed line of code:

BeanUtils.populate(new Student,request.getParameterMap());

Guess you like

Origin www.cnblogs.com/lixin-link/p/11222743.html