Simple learning of annotation reflection dynamic agent

Posted by ashleek007 on Sat, 26 Feb 2022 02:41:04 +0100

I annotation

Annotations in java implement the annotation interface by default. Generally, when we customize annotations, we mainly use two meta annotations (the other two @ Documented and @ Inherited have not been used much). See below

1.@Target

The main limitation is the type of java element to which annotations can be applied ElementType.ANNOTATION_TYPE can be applied to annotation types. ElementType.CONSTRUCTOR can be applied to constructors. ElementType.FIELD can be applied to fields or attributes. ElementType.LOCAL_VARIABLE can be applied to local variables. ElementType.METHOD can be applied to method level annotations. ElementType.PACKAGE can be applied to package declarations. ElementType.PARAMETER can be applied to the parameters of a method. ElementType.TYPE can be applied to any element of a class.

2.@Retention

RetentionPolicy.CLASS RetentionPolicy.SOURCE RetentionPolicy.RUNTIME

RetentionPolicy.CLASS

It is only kept in the source code and ignored by the compiler. The main application scenario is apt technology. The classes that can obtain annotations and annotation declarations during compilation, including all member information in the class, are generally used to generate additional auxiliary classes. There are also syntax checks, such as @ IntDef

RetentionPolicy.SOURCE

It will be reserved by the compiler, but will be ignored by the jvm. It is mainly used in bytecode enhancement technology. After compiling the Class, modify the Class data to achieve the purpose of modifying the code logic. Annotations can be used to distinguish whether it needs to be modified or to judge whether it needs to be modified into different logic.

RetentionPolicy.RUNTIME

It is mostly used to dynamically obtain annotation elements through reflection technology

Simple application

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface lengthTest {
    int max() default 0;
    int min() default  0;
    String dec() default "";
}

public class AnnLoginModel {

    private int age;

    @lengthTest(max = 10,min = 6,dec = "kkk")
    private String desc;

    public int getAge() {
        return age;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
    
}

 public static void vaild(Object o) throws Exception{
        Class<?> ls = o.getClass();
        Field[] fields = ls.getDeclaredFields();
        for (Field field:fields) {
            lengthTest lengthTest =  field.getAnnotation(lengthTest.class);
            if(lengthTest!=null){
                if(field.getGenericType().toString().equals("class java.lang.String")){
                    field.setAccessible(true);
                    String i = (String) field.get(o);
                    if(i.length()>lengthTest.min()&&i.length()< lengthTest.max()){
                        System.out.print("No more than");
                    }else{
                        System.out.print("exceed");
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        AnnLoginModel annLoginModel = new AnnLoginModel();
        annLoginModel.setAge(2);
        annLoginModel.setDesc("fool");
        vaild(annLoginModel);
    }

This is a simple example of parameter verification with annotation and reflection

II reflex

Reflection is to know all the properties and properties of any class in the running state method; For any object, you can call any of its methods and properties; And can change its properties. Is the key to Java being regarded as a dynamic language.

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    int value();
}

activity in

 @ViewInject(R.id.bt)
    Button bt;

    @ViewInject(R.id.tv)
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_annotation);
        MyViewInject.ViewInject(this);

    }

    public static void ViewInject(Activity activity) {
        Class<? extends Activity> ls = activity.getClass();
        for (Field field : ls.getDeclaredFields()) {
            ViewInject an = field.getAnnotation(ViewInject.class);//Judge whether it is a viewobject annotation
            if (an != null) {
                try {
                    field.setAccessible(true);//Set the access permission and allow to operate the property of private
                    Method method = ls.getDeclaredMethod("findViewById", int.class);//Take the findviewbyid method of activity. Of course, you can also directly use ls findviewbyid
                    View view = (View) method.invoke(activity, an.value());//method(ac,an.value): the first parameter sets the object on which to call, and the second parameter is the parameter of the method
                    field.set(activity, view);//Reflection field attribute assignment
                } catch (Exception e) {

                }
            }
        }

Simple example

1. Get class

Generally, it can be obtained by class name and object

2. Create an instance

You can use newinstance of class object or constructor newInstance There are a lot of lazy introductions to other methods

3. Disadvantages of reflection

Method#invoke requires automatic disassembly and assembly of the box Reflection needs to retrieve methods and parameters by name, and check the consistency of method visibility parameters. The compiler cannot optimize the dynamically invoked code, such as inline