Java literacy, further deepening -- Annotation annotation, user-defined annotation, and user-defined framework

Cognitive annotation

Annotations set metadata for program elements. It is essentially an interface.

Annotations are used to mark packages, classes, constructors, methods, member variables, parameters, and local variables.

However, annotations do not affect the execution of the program code.

If you want annotations to work in the program, you need a supporting annotation tool ATP(Annotation Processing Tool)

Common notes

Qualified Override parent method: @Override

People who learn Java must be familiar with @Override. When we implement an interface, the compiler automatically adds methods with this annotation. For example:

public class OverrideTest implements father{

	@Override
	public void m1() {
		// Method stubs automatically generated by TODO
		
	}

}
interface father {
	public void m1();
}

Function:

Tell the compiler that the following method is to rewrite the \ implementation method to let the compiler check for spelling errors. The advantage is to avoid low-level errors. In some compilers, there is basically no difference between O, O, 0 and 1, I and l. when we want to rewrite the parent method, we make errors because of this "small" problem, and this "small" problem is very, very difficult to troubleshoot!! (the lesson is too painful. No more examples...)

Other basic notes

Tag obsolete: @Deprecated

Illustration:

code

public class DeprecatedTest {

	public static void main(String[] args) {
		// Using obsolete methods will be warned
		new Apple().info();
	}
}

class Apple{
	// Define info method and set obsolete
	@Deprecated
	public void info() {
		System.out.println("Apple of info method");
	}
}

Suppress compiler warnings: @SuppressWarnings

Illustration:

code

import java.util.ArrayList;
import java.util.List;

public class SuppressWarningsTest {

	// Suppress warnings that do not have a type check operation
	@SuppressWarnings(value="unchecked")
	public static void main(String[] args) {
		// Ignore when using generics without specifying the corresponding type
		@SuppressWarnings("rawtypes")
		List myList = new ArrayList();
		myList.add("");
	}
	
}

Meta annotation of JDK

Existence stage: @Retention

Value value meaning
RetentionPolicy.SOURCE Annotations will be discarded by the compiler
RetentionPolicy.CLASS Annotations are available in the class file but are discarded by the VM
RetentionPolicy.RUNTIME The VM will also keep annotations at run time, so the annotation information can be read through the reflection mechanism

Specify elements that can be decorated: @Target

Value value meaning
ElemenetType.CONSTRUCTOR Constructor declaration
ElemenetType.FIELD Domain declaration (including enum instances)
ElemenetType.LOCAL_VARIABLE Local variable declaration
ElemenetType.METHOD Method declaration
ElemenetType.PACKAGE Package declaration
ElemenetType.PARAMETER Parameter declaration
ElemenetType.TYPE Class, interface (including annotation type) or enum declaration

Documents that can be converted by javadoc tool: @Documented

It means that this annotation will be extracted into a document by the javadoc tool.

Inherited by subclass: @inherited

Allow subclasses to inherit annotations from the parent class.

Custom annotation

Annotation structure

Click our common @Override to have a look

There are only two structures found:

  1. Meta annotation
  2. Annotation body

Test custom annotations

Let's imitate the above annotation and try to write an annotation.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface MyOverridn {

}

It seems that I don't understand it. Decompile it to see what it is.

Code generated after decompilation:

public class annotation.test.OverrideTest implements annotation.test.father {
  public annotation.test.OverrideTest();
  public void m1();
}

Now you can see. It is essentially a class that implements an interface

Here comes the point

As we said above, annotation is a label. If we make a label like this, it will not affect code execution. What is the use of annotation?

To make annotations play a greater role, you need to use reflection!

Reflection can get the elements marked by the annotation as follows.

Return value Method and explanation
<T extends Annotation> getAnnotation(Class annotationClass)
T If there are comments of the specified type for the element, these comments are returned; otherwise, null is returned.
Annotation[] getAnnotations()
Returns all comments that exist on this element.
Annotation[] getDeclaredAnnotations()
Returns all comments that exist directly on this element.
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
Returns true if the annotation of the specified type exists on this element; otherwise, returns false.

Annotation + reflection case

Anyone who has studied frame or reflection should have heard the words "frame is annotation + reflection" and "reflection is the soul of frame". Let's make two small "frames" to practice.

Only run methods with custom annotations

There are many methods of a class. Usually, we can adjust which one we want to use. Now, we need to use custom annotations to identify them, and then let these marked methods run. And record the number of exceptions.
Testable -- custom annotation

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// Specify how long the Testable annotation can be retained
@Retention(RetentionPolicy.RUNTIME)
// Specify the targets (only methods) that the Testable annotation can modify
@Target(ElementType.METHOD)
public @interface Testable {
	
}

MyTest -- there are classes that need to run methods

public class MyTest {
	
	@Testable
	public static void m1() {

	}

	public static void m2() {

	}
	@Testable
	public static void m3() {
		throw new RuntimeException("Boom");
	}

	public static void m4() {

	}
	@Testable
	public static void m5() {

	}

	public static void m6() {

	}
	@Testable
	public static void m7() {
		throw new RuntimeException("Crash");
	}

	public static void m8() {

	}
}

TestProcessor -- use reflection to load the identified method and run the core column

import java.lang.reflect.Method;

public class TestProcessor {

	public static void process(Class<MyTest> class1) throws SecurityException, ClassNotFoundException {
		int passed = 0;
		int failed = 0;
		for (Method m : class1.getMethods()) {
			if (m.isAnnotationPresent(Testable.class)) {
				try {
					m.invoke(null);
					passed++;
				} catch (Exception e) {
					System.out.println("method"+m+"Run failed, exception:"+e.getCause()+"\n");
					failed++;
				}
			}
		}
		System.out.println("A total of:"+(passed+failed)+"Methods, where\n"+
					"Failed:"+failed+"Pieces,\n"+
					"Succeeded:"+passed+"Pieces,\n"
				);
	}
}

RunTests -- call core classes

public class RunTests {
	public static void main(String[] args) throws Exception {
		TestProcessor.process(MyTest.class);
	}
}

Running results

method public static void annotation.useAnnotation.MyTest.m7()Run failed, exception: java.lang.RuntimeException: Crash

method public static void annotation.useAnnotation.MyTest.m3()Run failed, exception: java.lang.RuntimeException: Boom

A total of: 4 methods were run, of which
 Failed: 2,
Successful: 2,

Comment add button listens to "frame"

Learn JavaSE and play small games. I believe that button monitoring annoys many people. Each button needs to add monitoring one by one and write event processing one by one. It's better to add just one annotation
ActionListenerFor -- custom annotation

import java.awt.event.ActionListener;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionListenerFor {
	// Define a member variable to hold the listener implementation class
	Class<? extends ActionListener> listener();
}

ActionListenerInstaller - core processing class

import java.awt.event.ActionListener;
import java.lang.reflect.Field;

import javax.swing.AbstractButton;

public class ActionListenerInstaller {
	// A method for handling annotations, where obj is the object containing the annotation
	public static void processAnnotations(Object obj) {
		try {
			// Get the class of obj object
			Class cl = obj.getClass();
			// Get all member variables of the specified obj object and traverse each member variable
			for (Field f : cl.getDeclaredFields()) {
				// Make member variables freely accessible
				f.setAccessible(true);
				// Get Annotation of ActionListenerFor type on member variable
				ActionListenerFor a = f.getAnnotation(ActionListenerFor.class);
				// Get the value of member variable f
				Object fObj = f.get(obj);
				// If f is an instance of AbstractButton and a is not null
				if(a != null && fObj != null && fObj instanceof AbstractButton) {
					// Get the listener source data in the a annotation (it is a listening class)
					Class<? extends ActionListener > listennerClazz = a.listener();
					// Create an object of the listener class using reflection
					ActionListener al = listennerClazz.newInstance();
					AbstractButton ab = (AbstractButton)fObj;
					// Add an event listener for the ab button
					ab.addActionListener(al);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

AnnotationTest -- the class that needs to add the button (and the handling class of the button click event)

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class AnnotationTest {

	private JFrame mainWin = new JFrame("Binding event listeners with annotations");
	// Use annotations to bind event listeners for the ok button
	@ActionListenerFor(listener=OkListener.class)
	private JButton ok = new JButton("confirm");
	// Use annotations to bind event listeners for the cancel button
	@ActionListenerFor(listener=CancelListener.class)
	private JButton cancel = new JButton("cancel");
	
	public void init() {
		// Initialization interface
		JPanel jp = new JPanel();
		jp.add(ok);
		jp.add(cancel);
		mainWin.add(jp);
		ActionListenerInstaller.processAnnotations(this);
		mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainWin.pack();
		mainWin.setVisible(true);
	}
	public static void main(String[] args) {
		new AnnotationTest().init();
	}
}
// Define the event listener implementation class for the ok button
class OkListener implements ActionListener{
	@Override
	public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(null, "Click the confirm button");
	}
}
// Define the event listener implementation class for the cancel button
class CancelListener implements ActionListener{
	@Override
	public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(null, "Cancel button clicked");
	}
}

effect

Ask questions

After learning this, you should have a general answer to some questions in your heart.
For example:
Spring annotation @Table -- how to map objects to database data tables??
SpringMVC annotation @Autowired -- how to implement automatic injection??

Let yourself implement similar functions. Can you implement them?

Tags: Java reflection Framework Annotation

Posted by shaundunne on Mon, 30 May 2022 14:58:49 +0530