Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Definition of annotations

Java annotations have been added to Java since Java5 and are used to provide metadata to Java code. As metadata (see supplement 1), annotations do not directly affect your code execution, but there are some types of annotations that can actually be used for this purpose.

Annotations are labels: if you think of code as a living entity, annotations are labels to some individual of that code.

Annotation apis are very powerful and are widely used in Java frameworks such as Spring, Hibernate, JUnit, and Android Dagger2, ButterKnife, Retrofit, and more.

How to customize annotations

Annotations are defined by the @interface keyword.

public @interface Test {
}
Copy the code

It looks like an interface, but with an @ sign in front of it. The above code creates an annotation named Test. You can simply create a tag named Test.

Using annotations

@Test
public class TestAnnotation {
}
Copy the code

You can simply label the Test notation on top of the TestAnnotation class.

Create a class TestAnnotation and annotate the class with Test by adding @test in the class definition.

Three yuan notes

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.

A meta-annotation is a special tag that can be attached to other tags, and its purpose is to explain other common tags.

There are five meta-annotations: @Retention, @documented, @target, @Inherited, and @REPEATable.

3.1 @ Retention

Retention is Retention. When @Retention is applied to a annotation, it explains the annotation’s lifetime.

Its values are as follows:

RetentionPolicy.SOURCE Annotations are only retained at the source stage and are discarded and ignored when the compiler compiles.
RetentionPolicy.CLASS Annotations are only reserved until compilation takes place; they are not loaded into the JVM.
RetentionPolicy.RUNTIME Annotations can be kept until the application is run, and they are loaded into the JVM, so they can be retrieved while the application is running.

3.2 @ Target

Target means Target, @Target specifies where the annotation should be used so you can think of it this way, when a annotation is annotated by @Target, that annotation is restricted to the context in which it’s used. By analogy, tags can be posted anywhere you want, but thanks to @target, they can only be posted to methods, classes, method parameters, and so on.

@Target has the following values:

ElementType.ANNOTATION_TYPE You can annotate a annotation
ElementType.CONSTRUCTOR The constructor can be annotated
ElementType.FIELD Properties can be annotated
ElementType.LOCAL_VARIABLE Local variables can be annotated
ElementType.METHOD Methods can be annotated
ElementType.PACKAGE You can annotate a package
ElementType.PARAMETER You can annotate parameters within a method

3.3 @ Documented

As the name implies, this meta-annotation must be related to the document. It provides the ability to include elements from annotations into Javadoc. Elementtype. TYPE can annotate a TYPE, such as a class, interface, or enumeration.

3.4 @ Inherited

Inherited means Inherited, but it does not mean that the annotations themselves can be Inherited. It means that if a superclass is annotated by @Inherited annotations, then if its subclass is not applied by any annotations, it inherits the superclass’s annotations.

3.5 @ the Repeatable

Repeatable means Repeatable. Repeatable @repeatable was added to Java 1.8, so it’s a new feature.

What annotations are used more than once? Usually the value of an annotation can be multiple at the same time.

Java preset annotations

This is enough to allow us to define our own annotations, but Java already provides some annotations.

4.1 @ Deprecated

This element is used to mark obsolete elements. 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.

public class Stu {  

    @Deprecated
    public void getNameOld(a){
        System.out.println("This method is not recommended: Deprecated!");
    }

    public void getName(a){
        System.out.println("My name is Lucas");
    }


Copy the code

When you call the getNmaeOld() method of the above class in the IDE, you can see that the getNmaeOld() method is crossed out by a line, which is essentially a reminder of the compiler’s recognition.

4.2 @ Override

This is common among developers, prompting subclasses to Override the @Override method in their parent class.

4.3 @ SuppressWarnings

Prevent warning meaning. As mentioned earlier, the compiler will warn you when calling a method annotated by @deprecated, and sometimes developers will ignore this warning. They can do this by calling @SuppressWarnings from where they were called.

@SuppressWarnings("deprecation")
public void testSupressWarnings(a){
    Stu stu = new Stu();
    stu.getNameOld();
    stu.getName();
}
Copy the code

4.4 @ SafeVarargs

Parameter safety type annotations. Its purpose is to warn developers not to do anything unsafe with arguments, and its existence prevents compilers from generating such warnings. It was added in version 1.7 of Java.

@SafeVarargs // Not actually safe!
    static void m(List<String>... stringLists) {
    Object[] array = stringLists;
    List<Integer> tmpList = Arrays.asList(42);
    array[0] = tmpList; // Semantically invalid, but compiles without warnings
    String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}
Copy the code

In the above code, no errors are reported at compile time, but ClassCastException is thrown at runtime, so it tells the developer to take care of it, but the developer is still screwing up.

4.5 @ FunctionalInterface

Functional interface annotations, a new feature introduced in Java 1.8. Functional programming is hot, so Java 8 added this feature just in time. A Functional Interface is a plain Interface with a method. Such as:

@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.

One might wonder why functional interface tags are useful, because functional interfaces can be easily converted to Lambda expressions.

Attributes of annotations

5.1 Definition of attributes

Attributes of annotations are also called member variables. Annotations have only member variables and no methods. Note that properties defined in annotations must be of the eight basic data types plus classes, interfaces, annotations, and their array annotations can have default values, which need to be specified with the default key value.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
    int id(a) default 1;
    String msg(a) default "hello world";
}
Copy the code

The code above defines the TestAnnotation annotation that has 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

@Test(id=1, msg="hello annotation")
public class TestAnnotation {}Copy the code

5.2 Extraction of annotations

Annotation and reflection go hand in hand. Annotations are obtained by reflection. The Class object’s isAnnotationPresent() method first determines whether an annotation is applied:

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

We then retrieve the Annotation object using either getAnnotation() or getAnnotations(), which returns annotations of the specified type and any annotations annotated on this element:

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

public Annotation[] getAnnotations() {}
Copy the code

If the retrieved annotations are not null, then their property methods can be called:

@Test()
public class TestDemo{
	
public static void main(String[] args) {
	boolean hasAnnotation = TestDemo.class.isAnnotationPresent(Test.class);
		if ( hasAnnotation ) {
			TestAnnotation testAnnotation = TestDemo.class.getAnnotation(Test.class);
			System.out.println("id:"+testAnnotation.id());
			System.out.println("msg:"+testAnnotation.msg()); }}}Copy the code

In the above example, we just check out the annotations on the class. ** Annotations on properties and methods are still possible. The ** is also a reflex.

@TestAnnotation(msg="hello world")
public class Test {
	
	@Check(value="this is local value")
	int tempValue;
	
	
	@Perform
	public void testMethod(a){}
	
	
        // Do not hint that this is an obsolete method ide hint
	@SuppressWarnings("deprecation")
	public void testSuppressWarnings(a){
	    Stu stu = new Stu();
            stu.getNameOld();
            stu.getName();
	}
 
 
	public static void main(String[] args) {
		
		boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
		// Get the attribute information in the annotation
		if ( hasAnnotation ) {
			TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
			System.out.println("id:"+testAnnotation.id());
			System.out.println("msg:"+testAnnotation.msg());
		}
		
		// Get the member variables and method information of the annotated class
		try {
			Field tempValue = Test.class.getDeclaredField("tempValue");
			tempValue.setAccessible(true);
			// Get an annotation on a member variable
			Check check = tempValue.getAnnotation(Check.class);
			
			if( check ! =null ) {
				System.out.println("check value:"+check.value());
			}
			
			Method testMethod = Test.class.getDeclaredMethod("testMethod");
			
			if( testMethod ! =null ) {
				// Get the annotation in the method
				Annotation[] ans = testMethod.getAnnotations();
				for( int i = 0; i < ans.length; i++) { System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName()); }}}catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println(e.getMessage());
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println(e.getMessage());
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch blocke.printStackTrace(); System.out.println(e.getMessage()); }}}Copy the code

Running results:

id:1
msg:hello world
check value:hi
method testMethod annotation:Perform
Copy the code

Usage scenarios of annotations

  • Provide information to the compiler: The compiler can use annotations to detect errors and warnings
  • Compile-time processing: Software tools can be used to generate code, Html documents, or other processing using annotation information.
  • Runtime processing: Some annotations can be extracted from the code while the program is running. It is important to note that annotations are not part of the code itself.

In the official documentation, annotations are mainly for compilers and other SoftWare tools. 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).

So what are annotations for? For who? A: For compiler or APT or other tool type software. It is worth noting that annotation extraction requires Java reflection, which is slow, so annotation usage requires consideration of the time cost.

A simple test framework for actual practice

With annotations, we can write simple test frameworks in our code with minimal invasiveness. Start by defining an annotation that needs to be added when tested:

@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleTest {

}
Copy the code

Next, add the annotation to the section of code we want to test, using method tests as an example:

public class BugCodeAutoTest {
	
	@SimpleTest
	public void divideZero(a){
		System.out.println("1/0 =" + 1 / 0);
	}
	
        @SimpleTest
	public void normalFun(a){
		System.out.println("1 + 1 =" + (1 +1)); }}Copy the code

At this point, we can write the test tool class:

public class TestTool {
 
	public static void main(String[] args) {
 
		BugCodeAutoTest bugCodeAutoTest = new BugCodeAutoTest();
		Class clazz = bugCodeAutoTest.getClass();
		
		Method[] method = clazz.getDeclaredMethods();
		// To record the log information generated by the test
		StringBuilder log = new StringBuilder();
		// Record the number of exceptions
		int errornum = 0;
		
		for ( Method m: method ) {
			// Test the methods labeled by @simlpetest
			if ( m.isAnnotationPresent( SimlpeTest.class )) {
				try {
					m.setAccessible(true);
					m.invoke(bugCodeAutoTest, null);
				
				} catch (Exception e) {
					
					//e.printStackTrace();
					errornum++;
					log.append(m.getName());
					log.append("");
					log.append("has error:");
					log.append("\n\r caused by ");
					// Record the name of the exception that occurred during the test
					log.append(e.getCause().getClass().getSimpleName());
					log.append("\n\r");
					// Record specific information about exceptions that occur during the test
					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

Running results:

 divideZero has error:

  caused by ArithmeticException

  by zero

BugCodeAutoTest has  1 error.
Copy the code

Invoke (Object obj,Object… The first argument is an instance of the class, and the second argument is an argument in the corresponding function. Method. Invoke (object, new object [][]{new object []{obj1, obj2}}), which is equivalent to Object.method (obj1, obj2) :

method2.invoke(test, new String[][]{new String[]{"a"."b"}});
Copy the code

Supplement 1: Metadata

The term define
metadata Data about data. The goal of JSR-175 is to provide metadata facilities in the Java language.
notation A special Java structure that decorates classes, methods, fields, parameters, variables, constructors, or packages. It is the tool chosen by JSR-175 to provide metadata.
Notation type Various naming annotations with special implementations
attribute A special metadata item specified by an annotation. Sometimes used interchangeably with notes

For example: Fuji apple has one property: it is red. Given a FujiApple class, you can specify its Color using an annotation of the @color annotation type. By doing so, you provide metadata about apple.

Metadata, translated from the word metadata, is “data about data”, which describes the structural information of data. Metadata can be used for many purposes. For example, you may have used Javadoc comments to generate documents automatically. This is one kind of metadata capability. In general, metadata can be used to create documentation, track code dependencies, perform compile-time formatting checks, and replace existing configuration files.

In Java, metadata exists in Java code in the form of tags. The presence of metadata tags does not affect the compilation and execution of program code, and is used to generate other files or only at runtime to know the description of the code being run.

Its functions are as follows:

Generate documentation: This is the most common and earliest annotation provided in Java. @param@return;

Tracking code dependencies to replace configuration files. A common one is the annotation-based configuration starting with Spring 2.5. The effect is to reduce configuration. Most frameworks today use this configuration to reduce the number of configuration files. ;

③ Check the format at compile time. If @Override comes before a method, it will be checked at compile time if your method does not override a superclass method.

Reference article:

Take full advantage of Java metadata

Java annotations (annotations) You can learn this:

Java Annotations – Metadata, annotation classification, built-in annotations, and custom annotations: