Java annotations are shallow in and deep out

This article mainly refers to and draws lessons from frank909 article, but is more simple, detailed.

Annotation is the definition of Annotation. An Annotation is a special modifier that applies to classes, methods, parameters, variables, constructors, and package declarations. It is a tool chosen by the JSR-175 standard to describe metadata. Annotations are a very important knowledge point in Java, annotations are very popular, many mainstream frameworks support annotations, and their own code will try to use annotations, one is convenient, the second is more concise code.

Annotation syntax

Because the common development is rare, I believe that many people will think that the status of annotations is not high. Annotations are of a type, just like classs and interfaces. It was introduced in Java SE 5.0.

package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a supertype. If a method is annotated with
 * this annotation type compilers are required to generate an error
 * message unless at least one of the following conditions hold:
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * </li></ul>
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
Copy the code

It looks like an interface, but with an @ sign in front of it. The above code creates an annotation named Override.

You can simply create a tag named Override.

Annotations **Annotations are just metadata and have nothing to do with business logic. It’s a little hard to understand, but there you go. If Annotations don’t contain business logic, someone has to implement that logic. Metadata users to do this. Annotations only provide information about the attributes (class/method/package/domain) it defines. Annotations’ users (again, some code) read this information and implement the necessary logic.

Yuan notes

What does a meta-annotation mean?

A meta-comment is a comment that can be added to a comment, or a meta-comment is a basic comment that can be applied to other comments.

If it’s hard to understand, you can understand it like this. A meta-annotation is also a tag, but it is a special tag whose function and purpose is to explain other common tags.

There are @Retention, @documented, @target (when an annotation is annotated by @target, the annotation is defined by the application scenario), @Inherited, and @REPEATable.

@target To indicate where the annotation can be used, possible ElementType arguments are: CONSTRUCTOR: declaration of the CONSTRUCTOR FIELD: declaration of the FIELD (including enum instances) LOCAL_VARIABLE: declaration of the local variable METHOD: declaration of the METHOD PACKAGE: Package declaration PARAMETER: PARAMETER declaration TYPE: class, interface (including annotation TYPE), or enum declaration
@Retention Indicates the level at which the annotation information needs to be saved. Optional RetentionPolicy parameters include: SOURCE: annotations will be discarded by the compiler; CLASS: Annotations are available in the CLASS file, but are discarded by the VM; RUNTIME: The VM will retain annotations during RUNTIME, so they can be read by reflection.
@Document Include annotations in Javadoc
@Inherited Allows subclasses to inherit annotations from their parent class
@Repeatable Repeatable (@repeatable is Java 1.8)

Attributes of annotations

Attributes of annotations are also called member variables. Annotations have only member variables and no methods. An annotation’s member variable is declared in the annotation definition as a method of invisible parameters, whose method name defines the name of the member variable, and whose return value defines the type of the member variable. Note that the type of an attribute defined in an annotation must be the eight basic data types plus classes, interfaces, annotations, and their arrays.

Attributes in annotations can have default values, which need to be specified with the default key value.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Person {
    int id(a) default- 10998.;

    String msg(a) default "no hello";

}

Copy the code

The code above defines the Person annotation to have the ID and MSG attributes. When used, we should assign values to them. This is done by enclosing the annotation in parentheses with the form value= “”, separated from multiple attributes by a comma. When an annotation contains only one attribute named value, the annotation can be filled in parentheses with the attribute value. Also note that an annotation does not have any attribute parentheses that can be omitted.

public @interface NoUse {
}
Copy the code
public @interface Chou {
    String value(a) default "You";
}
Copy the code
@Person(id = 10758, msg = "hello android")// Default @person ()
public class Liming {
    @Chou("She")
    String beautiful;

    @NoUse
    public void say(a) {}}Copy the code

Java preconfigured annotations

The Java language itself already provides several off-the-shelf annotations.

@Deprecated

This element is used to mark obsolete elements, which you might encounter in your daily development. When the compiler encounters this annotation at compile time, it will issue a reminder warning that the developer is calling an outdated element such as an outdated method, an outdated class, or an outdated member variable.

@Person(id = 10758, msg = "hello android")// Default @person ()
public class Liming {
    @Chou("She")
    String beautiful;

    @NoUse
    public void say(a) {
        System.out.println(" say is using ");
    }

    @Deprecated
    public void speak(a) {
        System.out.println(" speak is out of date "); }}Copy the code

The Liming class, which has two methods say() and speak(), of which speak() is annotated by @deprecated. We then call them separately from the IDE.

As you can see, the speak() method is crossed with a line, which is essentially a reminder of the compiler’s recognition.

@SuppressWarnings

Block warnings. The compiler will warn you when calling a method annotated with @deprecated, and developers will sometimes ignore this warning. They can do this by calling @SuppressWarnings from where they were called.

@SafeVarargs

Parameter safety type annotations. Its purpose is to warn developers against doing things that are unsecure with arguments, and its presence will prevent compilers from generating warnings like those added to Java 1.7.

In the above code, no errors are reported at compile time and ClassCastException is thrown at run time.

@FunctionalInterface

Functional interface annotations, a new feature introduced in Java 1.8.

A Functional Interface is a plain Interface with a method.

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run(a);
}
Copy the code

The Runnable we use in threaded development is a typical FunctionalInterface annotated by @functionalinterface.

For those of you who might be confused, the functional interface flag, functional interfaces can be easily converted to Lambda expressions.

Annotations and reflections

  • Annotations are obtained by reflection. You can first determine whether an annotation is applied to a Class object using the isAnnotationPresent() method

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

  • The Annotation object is then obtained using the getAnnotation() method.

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

  • Or getAnnotations().

public Annotation[] getAnnotations() {}

  • The former method returns the annotations of the specified type, and the latter method returns all annotations annotated to the element.

If the annotations you get are not null, then you can call their property methods.

Annotations on properties and methods are also ok. Again, it’s reflection.

public static void getAnnotation(a) {
    boolean hasAnnotation = MainActivity.class.isAnnotationPresent(Person.class);
    if (hasAnnotation) {
        Person testPerson = MainActivity.class.getAnnotation(Person.class);
        System.out.println("id is " + testPerson.id() + " msg is "+ testPerson.msg()); }}public static void getField(a) {
        try {
            Field a = Liming.class.getDeclaredField("beautiful");
            a.setAccessible(true);
            Chou chou = a.getAnnotation(Chou.class);
            if(chou ! =null) {
                System.out.println("check value:" + chou.value());
            }
            Method noUse = Liming.class.getDeclaredMethod("say");
            if(noUse ! =null) { // Get the annotation in the method
                Annotation[] ans = noUse.getAnnotations();
                for (int i = 0; i < ans.length; i++) {
                    System.out.println("method noUse annotation:"+ ans[i].annotationType().getSimpleName()); }}}catch (NoSuchFieldException e) {
            e.printStackTrace();
            System.out.println("NoSuchFieldException");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            System.out.println("NoSuchMethodException"); }}Copy the code
 say is using 
 speak is out of date 
id is -10998 msg is this is not default
check value:She
method noUse annotation:NoUse

Process finished with exit code 0
Copy the code

When the developer modiifies the class, method, Field and other members with annotations, these annotations will not take effect by themselves. The developer must provide the corresponding code to extract and process Annotation information. These codes that extract and process annotations are called APT (Annotation Processing Tool).

Annotations are a set of metadata that provides data to interpret program code, but annotations are not part of the interpreted code itself. Annotations have no direct effect on how the code works. Annotations have many uses, mainly as follows: - Provide information to the compiler: the compiler can use annotations to detect errors and warnings - compile-time processing: software tools can use annotations to generate code, Html documents, and other processing. - Runtime processing: Some annotations can accept code extraction while the program is runningCopy the code

Personally customize annotations to accomplish a purpose

Requirements: custom annotations and implementations, checking for errors in MaSaGei classes and feedback

@Retention(RetentionPolicy.RUNTIME)
public @interface CheckOut {
}
Copy the code
public class MaSaGei {
    @CheckOut
    public void testOne(a) {
        System.out.println("1 + 0 =" + ((1 + 1) / 2));
    }

    @CheckOut
    public void testTwo(a) {
        System.out.println("1 + 1 =" + (8 / 4));
    }

    @CheckOut
    public void testThree(a) {
        System.out.println("1 + 2 =" + (6 / 2));
    }

    @CheckOut
    public void testFour(a) {
        System.out.println("1/3 =" + (6 / 0)); }}Copy the code
public class CheckOutTool {
    public static void checkAll(a) {
        MaSaGei maSaGei = new MaSaGei();
        Class clazz = maSaGei.getClass();
        Method[] method = clazz.getDeclaredMethods();
        StringBuilder log = new StringBuilder();
        // Record the number of exceptions
        int errornum = 0;
        for (Method m : method) {
            if (m.isAnnotationPresent(CheckOut.class)) {
                m.setAccessible(true);
                try {
                    m.invoke(maSaGei, null);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                    errornum++;
                    log.append(m.getName());
                    log.append("");
                    log.append("has error ");
                    log.append("\\n\\r caused by ");
                    log.append(e.getCause().getClass().getSimpleName());
                    log.append("\n\r");
                    log.append(e.getCause().getMessage());
                    log.append("\n\r");
                }
            }
        }
        log.append(clazz.getSimpleName());
        log.append(" has ");
        log.append(errornum);
        log.append(" error."); // Generate a test reportSystem.out.println(log.toString()); }}Copy the code

The results are as follows:

testFour  has error \n\r  caused by ArithmeticException
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.heng.subhey.annotation.CheckOutTool.checkAll(CheckOutTool.java:18)
	at com.heng.subhey.MainActivity.main(MainActivity.java:22)
Caused by: java.lang.ArithmeticException: / by zero
/ by zero
	at com.heng.subhey.annotation.MaSaGei.testFour(MaSaGei.java:21)
	... 6 more
MaSaGei has  1 error.

Process finished with exit code 0
Copy the code

Annotation Application Example

JUnit

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect(a) throws Exception {
       assertEquals(4.2 + 2); }}Copy the code

@test marks the method to be tested with addition_isCorrect().

ButterKnife

ButterKnife is one of the most well-known IOC frameworks in Android development, which reduces a lot of repetitive code.

public class GoPayActivity extends BaseActivity {
    @BindView(R.id.title_tv)
    TextView title_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        title_tv.setText("Pay");
    }

    @Override
    protected int getLayoutId(a) {
        return R.layout.activity_go_pay;
    }

    @OnClick({R.id.title_back, R.id.pay_confirm})
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.title_back:
                finish();
                break;
            case R.id.pay_confirm:
                ToastUtils.showLong("Payment environment security testing...");
                title_tv.postDelayed(new Runnable() {
                    @Override
                    public void run(a) {
                        ToastUtils.showShort("Jump to payment page soon");
                        Intent charge = new Intent(GoPayActivity.this, KeyWriteActivity.class); startActivity(charge); }},2 * 1000);
                break; }}}Copy the code

Retrofit

Http network access framework

public interface GitHubService { @GET("users/{user}/repos") 
Call<List<Repo>> listRepos(@Path("user") String user); } 
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class);
Copy the code

conclusion

  • Annotations are difficult to understand. Annotations explain code.
  • Basic syntax for annotations, with an extra @ sign.
  • Meta-annotations of annotations.
  • Attributes of annotations.
  • Annotations are intended for compiler and tool-type software.
  • Annotation extraction requires the use of Java reflection technology, reflection is slow, so annotations need to be used carefully with time costs.