Hello everyone, I am xiao CAI, a desire to do CAI Not CAI xiao CAI in the Internet industry. Soft but just, soft praise, white piao just! Ghost ~ remember to give me a three – even oh!

This article focuses on the use of annotations in Java

Refer to it if necessary

If it is helpful, do not forget the Sunday

Wechat public number has been opened, xiao CAI Liang, did not pay attention to the students remember to pay attention to oh!

The recent series of articles I believe you have also found, are some of the more basic Java knowledge. But I do not know in everyone after reading have feel is some very basic knowledge points, looks very simple, in fact there are a lot of content will not. Only with a solid foundation, development can be more efficient, do not rush to success, might as well turn back to pragmatic, do not have a harvest. So this time, as usual, Xiao CAI and his friends will learn how to use annotations.

I met

Annotations are also called metadata. It gives us a formal way to add information to our code, making it very easy to use that data at a later point.

Annotations, introduced after Java 1.5, provide a complete description of the information needed in a program, a format that can be tested and verified by the compiler, and store additional information about the program.

Annotations are easy to use, just with the @ symbol. Some Java novices often confuse annotations with comments, but they are used to describe information. The difference is that the information described by annotations is for the application, while the information described by annotations is for the developer.

Beginners may not be impressed by annotations, which may be obscure but can be seen everywhere.

The most common is @override, which means that the current method definition overrides the method of the parent class, and the compiler will issue an error message if it is misspelled or if the method signature does not match the overridden method.

Now that we’re talking about @Override, the @Suppresswarnnings annotation probably comes to mind if you think about it. I remember the first time I saw this annotation, when Myeclipse prompted me to use it, AND I didn’t care. It turns out that this annotation is used to turn off compiler warnings about class, method, member variable, and variable initialization.

Having said that, let’s do another one, which is probably the least common. That is the @ Deprecated

Don’t be surprised if this class is underlined, it’s because of the @deprecated effect. Its specific function is to identify a method or a class, indicating that the class or method is outdated and not recommended. If a developer uses an element annotated as it, the compiler issues a warning message.

In the beginning, we have already learned the use of three annotations, which are just basic, but let’s use these three annotations to make traverse levels weird.

Guan Zhicheng wa made note

Once constructed, annotations enjoy the compiler’s type-checking protection. Let’s warm up with the next set of code:

public class TestService {

    @MyAnnotation
    public void runTset(a) {
        System.out.println("annotation test"); }}Copy the code

Don’t be surprised, there isn’t an annotation called MyAnnotation in Java, but how did we get there? We made it ourselves.

Now that we’ve sold out, here’s how the notes are made:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
Copy the code

In this way, a simple note was made. Note that this is not an interface, you need to leave a message interface before there is an @ symbol, if this symbol is missed, it can be very different.

Those of you who are careful may have noticed that there is a note at the end of the definition.

That’s what I’m going to talk about. Tap on the blackboard. Pay attention!

Meta annotations to help

When you define annotations, you need some meta-annotations. There are two of them, at sign Target and at Retention.

Where @target is used to define where your annotation will be applied to (such as a method or field), @retention is used to define at what level the annotation is available, in SOURCE (SOURCE), in a CLASS file (CLASS), or at RUNTIME (RUNTIME). Java provides four types of meta-annotations, as follows:

The name of the use
@Target Identifies where the annotation can be used. Among themElementTypeParameters include:

1. CONSTARUCTOR: constructor declaration

2. FIELD: Domain declaration (including enum instances)

3. LOCAL_VARIABLE: local variable declaration

4. METHOD: method declaration

5. PACKAGE: package declaration

6. TYPE: class, interface (including annotation type), or enum declaration
@Retention Indicates the level at which the annotation information needs to be saved, whereRetentionPolicyParameters include:

1.SOURCE: Comments are discarded by the compiler

2.CLASSAnnotations are available in the class file, but are discarded by the VM

3. RUNTIME: THE VM will also retain annotations at run time, so they can be read by reflection
@Documented Include this annotation in JavaDoc
@Inherited An annotation that allows a subclass to inherit from its parent

Annotations are also classified

We created an @myAnnotation annotation in the example above. It looks very simple and doesn’t have much content, so this kind of annotation is also called tag annotation, and there are several types of annotations:

  • Tag annotationThere are no attributes inside annotations. Usage:@ annotation name
/ / define
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
Copy the code
  • Single value annotationThere is only one attribute inside the annotation. Usage:@ Annotation name (key = value)
/ / define
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SingleValueAnnotation {
    String name(a);
}
/ / use
@SingleValueAnnotation(name = "test")
public void singleTest(a) {}
Copy the code
  • Multivalued annotationsThere was an attribute inside the annotation. Usage:@ Annotation name (key = value, key = value,…)
/ / define
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiValueAnnotation {
    String name(a);
    int num(a);
}
/ / use
@MultiValueAnnotation(name = "test", num = 1)
public void multiTest(a) {}
Copy the code

Values also have defaults

When we use non-markup annotations, if we do not assign values to the attributes in the annotation when we use the annotation, the compiler will report an error indicating that we need to assign values.

This is very inconvenient. Sometimes we do not use it or the value is fixed and we do not want to write it repeatedly. At this time, we need to use the default keyword to help us solve this problem.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MultiValueAnnotation {
    
    String name(a);
    
    int num(a) default 0;
}
Copy the code

We use the default keyword on the property to declare that the num property defaults to 0, so that we don’t have to manually assign num when we use the above annotation.

Second key to the machine solution

Annotations are useful for compilation checks by the compiler, but without a tool to read them, annotations are no more useful than comments, which at least make it easier for developers to see what the code is doing.

To return to the reflection

To create and use annotation processors, we also need to build such tools with reflection mechanisms. Here’s a simple example:

public class AnnotationHandle {

    public static void track(Class
        c) {
        for (Method m : c.getDeclaredMethods()) {
            MultiValueAnnotation annotation = m.getAnnotation(MultiValueAnnotation.class);
            if(annotation ! =null) {
                System.out.println("name:" + annotation.name() +
                        "\n num:"+ annotation.num()); }}}public static void main(String[] args) { track(TestService.class); }}/* OUTPUT: name:test num:0 */
Copy the code

In the example above we used two reflection methods: getDeclaredMethods() and getAnnotation().

GetDeclaredMethods () returns all the methods for the class, and getAnnotation() gets the annotation object of the specified type. Null is returned if the annotation is not present on the method.

Annotation element available types

In the @multiValueAnnotation annotation above we define a String name and an int num. There are other types we can use:

  • Basic types (int, float, Boolean, etc.)
  • String
  • Class
  • enum
  • Annotation
  • An array of the above types

If any other type is used, the compiler will report an error. Also note that you can’t use primitive wrapper types either

Default limits

In the example above, we can see, we can give annotations when using annotations to attribute assignment, has also been defined in the annotations to annotate a default value, but both shows one thing: that is, the annotation element cannot have uncertain value, or has a default value, or provide the value of the element when using annotations

Base elements do not have null values, so elements of non-base types, either declared in use or at definition, cannot have a null value as their value. So in real development, we tend to define special values as nonexistent identifiers, such as negative numbers or empty strings

Good luck is the best strategy

In the previous two chapters, we learned to define annotations and create annotation handlers. Next, let’s go deeper into annotations!

Annotations can also be nested

When we’re modifying an Annotation element and we see that we can use annotations to modify it, it’s probably a little weird when we see that. I’m here to reveal it for you.

Let’s start with a set of notes:

@Constraints

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
    boolean primaryKey(a) default false;
    boolean unique(a) default false;
}
Copy the code

@SQLString

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
    String name(a) default "";
    Constraints constraints(a) default @Constraints;
}
Copy the code

We use the Constraints annotation element in the @SQLString annotation and set the default value to @constraints. At this point, the values in Constraints are the default values defined in the @constraints annotation. If we wanted to use custom values, we would do as follows:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
    String name(a) default "";
    Constraints constraints(a) default @Constraints(primaryKey = true);
}
Copy the code

That way we can use our own value

Annotations do not support inheritance

We can’t use extends to inherit an @interface, but we can get around this annoyance by nesting it.

AOP with annotations

AOP is not new to development today, so how can AOP and annotations generate chemistry? Take a look at the following code:

@ ApiLog:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface ApiLog {
    /**
     * 接口名称
     */
    String name(a);
}
Copy the code

Use:

@GetMapping(value = "/getConfig")
@apilog (name = "system related configuration ")
public Result getConfig(a) throws Exception {
    return sendOK(SystemService.getConfig(type));
}
Copy the code

Aop use:

@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private LogService logService;
    
    @Pointcut("@annotation(cbuc.life.annotation.ApiLog)")
    public void logPointCut(a) {}@Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // Execute method
        Object result = point.proceed();
        // Execution time (ms)
        long time = System.currentTimeMillis() - beginTime;
        // Save the log
        saveSysLog(point, time);
        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        LogEntity log = new LogEntity();
        ApiLog apiLog = method.getAnnotation(ApiLog.class);
        if(apiLog ! =null) {// The description in the annotation
            log.setMethodDescribe(syslog.value());
        }

        // The method name of the request
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.setMethod(className + "." + methodName + "()");

        // Request parameters
        Object[] args = joinPoint.getArgs();
        String params = JSON.toJSONString(args[0]);
        log.setParams(params);

        / / get request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        // Set the IP address
        log.setIp(ServletUtil.getIpAddress(request));

        / / user name
        String username = LoginInfo.getUsername();
        log.setUsername(username);

        // Save system logslogService.save(log); }}Copy the code

With the above code, we can add @apilog annotation to the method we want to log. The actions of the method are logged into the log table, regardless of the name of the method or the location of the class. This can be easily resolved without code intrusion.

Here, we have successfully passed three levels, I believe you have fully mastered the use of annotations, annotations we end here, remember: not because of the small and not because of the big and abandoned.

Today you work harder, tomorrow you will be able to say less words!

I am xiao CAI, a man who studies with you. 💋

Wechat public number has been opened, xiao CAI Liang, did not pay attention to the students remember to pay attention to oh!