22.6 C
New York
Wednesday, July 3, 2024

How one can describe Java code with annotations


You’ve in all probability encountered conditions the place you might want to affiliate metadata (knowledge that describes different knowledge) with courses, strategies, and/or different software parts. For instance, your programming group may must establish unfinished courses in a big software. For every unfinished class, the metadata would seemingly embody the title of the developer liable for ending the category and the category’s anticipated completion date.

Earlier than Java 5, feedback had been the one versatile mechanism that Java needed to supply for associating metadata with software parts. Nevertheless, feedback are a poor selection. As a result of the compiler ignores them, feedback are usually not obtainable at runtime. And even when they had been obtainable, the textual content must be parsed to acquire essential knowledge gadgets. With out standardizing how the information gadgets are specified, these knowledge gadgets may show unattainable to parse.

obtain

Obtain the supply code for examples on this Java 101 tutorial. Created by Jeff Friesen for InfoWorld.

Java 5 modified the whole lot by introducing annotations, an ordinary mechanism for associating metadata with varied software parts. This mechanism consists of 4 elements:

  • An @interface mechanism for declaring annotation sorts.
  • Meta-annotation sorts, which you should utilize to establish the appliance parts to which an annotation kind applies; to establish the lifetime of an annotation (an occasion of an annotation kind); and extra.
  • Assist for annotation processing through an extension to the Java Reflection API (to be mentioned in a future article), which you should utilize to find a program’s runtime annotations, and a generalized device for processing annotations.
  • Commonplace annotation sorts.

I’ll clarify how one can use these elements as we work our method by means of this text.

Declaring annotation sorts with @interface

You may declare an annotation kind by specifying the @ image instantly adopted by the interface reserved phrase and an identifier. For instance, Itemizing 1 declares a easy annotation kind that you just may use to annotate thread-safe code.

Itemizing 1: ThreadSafe.java

public @interface ThreadSafe
{
}

After declaring this annotation kind, prefix the strategies that you just take into account thread-safe with situations of this sort by prepending @ instantly adopted by the kind title to the strategy headers. Itemizing 2 provides a easy instance the place the predominant() technique is annotated @ThreadSafe.

Itemizing 2: AnnDemo.java (model 1)

public class AnnDemo
{
   @ThreadSafe
   public static void predominant(String[] args)
   {
   }
}

ThreadSafe situations provide no metadata aside from the annotation kind title. Nevertheless, you’ll be able to provide metadata by including parts to this sort, the place an aspect is a technique header positioned within the annotation kind’s physique.

In addition to not having code our bodies, parts are topic to the next restrictions:

  • The strategy header can’t declare parameters.
  • The strategy header can’t present a throws clause.
  • The strategy header’s return kind should be a primitive kind (e.g., int), java.lang.String, java.lang.Class, an enum, an annotation kind, or an array of one in every of these sorts. No different kind could be specified for the return kind.

As one other instance, Itemizing 3 presents a ToDo annotation kind with three parts figuring out a specific coding job, specifying the date when the job is to be completed, and naming the coder liable for finishing the job.

Itemizing 3: ToDo.java (model 1)

public @interface ToDo
{
   int id();
   String finishDate();
   String coder() default "n/a";
}

Observe that every aspect declares no parameter(s) or throws clause, has a authorized return kind (int or String), and terminates with a semicolon. Additionally, the ultimate aspect reveals {that a} default return worth could be specified; this worth is returned when an annotation doesn’t assign a price to the aspect.

Itemizing 4 makes use of ToDo to annotate an unfinished class technique.

Itemizing 4: AnnDemo.java (model 2)

public class AnnDemo
{
   public static void predominant(String[] args)
   {
      String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", 
                          "Paris", "London" };
      type(cities);
   }

   @ToDo(id = 1000, finishDate = "10/10/2019", coder = "John Doe")
   static void type(Object[] objects)
   {
   }
}

Itemizing 4 assigns a metadata merchandise to every aspect; for instance, 1000 is assigned to id. In contrast to coder, the id and finishDate parts should be specified; in any other case, the compiler will report an error. When coder isn’t assigned a price, it assumes its default "n/a" worth.

Java supplies a particular String worth() aspect that can be utilized to return a comma-separated record of metadata gadgets. Itemizing 5 demonstrates this aspect in a refactored model of ToDo.

Itemizing 5: ToDo.java (model 2)

public @interface ToDo
{
   String worth();
}

When worth() is an annotation kind’s solely aspect, you don’t must specify worth and the = project operator when assigning a string to this aspect. Itemizing 6 demonstrates each approaches.

Itemizing 6: AnnDemo.java (model 3)

public class AnnDemo
{
   public static void predominant(String[] args)
   {
      String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", 
                          "Paris", "London" };
      type(cities);
   }

   @ToDo(worth = "1000,10/10/2019,John Doe")
   static void type(Object[] objects)
   {
   }

   @ToDo("1000,10/10/2019,John Doe")
   static boolean search(Object[] objects, Object key)
   {
      return false;
   }
}

Utilizing meta-annotation sorts — the issue of flexibility

You may annotate sorts (e.g., courses), strategies, native variables, and extra. Nevertheless, this flexibility could be problematic. For instance, you may wish to prohibit ToDo to strategies solely, however nothing prevents it from getting used to annotate different software parts, as demonstrated in Itemizing 7.

Itemizing 7: AnnDemo.java (model 4)

@ToDo("1000,10/10/2019,John Doe")
public class AnnDemo
{
   public static void predominant(String[] args)
   {
      @ToDo(worth = "1000,10/10/2019,John Doe")
      String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", 
                          "Paris", "London" };
      type(cities);
   }

   @ToDo(worth = "1000,10/10/2019,John Doe")
   static void type(Object[] objects)
   {
   }

   @ToDo("1000,10/10/2019,John Doe")
   static boolean search(Object[] objects, Object key)
   {
      return false;
   }
}

In Itemizing 7, ToDo can also be used to annotate the AnnDemo class and cities native variable. The presence of those faulty annotations may confuse somebody reviewing your code, and even your individual annotation processing instruments. For the occasions when you might want to slender an annotation kind’s flexibility, Java provides the Goal annotation kind in its java.lang.annotation bundle.

Goal is a meta-annotation kind — an annotation kind whose annotations annotate annotation sorts, versus a non-meta-annotation kind whose annotations annotate software parts, resembling courses and strategies. It identifies the sorts of software parts to which an annotation kind is relevant. These parts are recognized by Goal’s ElementValue[] worth() aspect.

java.lang.annotation.ElementType is an enum whose constants describe software parts. For instance, CONSTRUCTOR applies to constructors and PARAMETER applies to parameters. Itemizing 8 refactors Itemizing 5’s ToDo annotation kind to limit it to strategies solely.

Itemizing 8: ToDo.java (model 3)

import java.lang.annotation.ElementType;
import java.lang.annotation.Goal;

@Goal({ElementType.METHOD})
public @interface ToDo
{
   String worth();
}

Given the refactored ToDo annotation kind, an try to compile Itemizing 7 now ends in the next error message:

AnnDemo.java:1: error: annotation kind not relevant to this sort of declaration
@ToDo("1000,10/10/2019,John Doe")
^
AnnDemo.java:6: error: annotation kind not relevant to this sort of declaration
      @ToDo(worth="1000,10/10/2019,John Doe")
      ^
2 errors

Further meta-annotation sorts

Java 5 launched three further meta-annotation sorts, that are discovered within the java.lang.annotation bundle:

  • Retention signifies how lengthy annotations with the annotated kind are to be retained. This sort’s related java.lang.annotation.RetentionPolicy enum declares constants CLASS (compiler information annotations at school file; digital machine doesn’t retain them to avoid wasting reminiscence — default coverage), RUNTIME (compiler information annotations at school file; digital machine retains them), and SOURCE (compiler discards annotations).
  • Documented signifies that situations of Documented-annotated annotations are to be documented by javadoc and comparable instruments.
  • Inherited signifies that an annotation kind is robotically inherited.

Java 8 launched the java.lang.annotation.Repeatable meta-annotation kind. Repeatable is used to point that the annotation kind whose declaration it (meta-)annotates is repeatable. In different phrases, you’ll be able to apply a number of annotations from the identical repeatable annotation kind to an software aspect, as demonstrated right here:

@ToDo(worth = "1000,10/10/2019,John Doe")
@ToDo(worth = "1001,10/10/2019,Kate Doe")
static void type(Object[] objects)
{
}

This instance assumes that ToDo has been annotated with the Repeatable annotation kind.

Processing annotations

Annotations are supposed to be processed; in any other case, there’s no level in having them. Java 5 prolonged the Reflection API that will help you create your individual annotation processing instruments. For instance, Class declares an Annotation[]
getAnnotations()
technique that returns an array of java.lang.Annotation situations describing annotations current on the aspect described by the Class object.

Itemizing 9 presents a easy software that hundreds a category file, interrogates its strategies for ToDo annotations, and outputs the elements of every discovered annotation.

Itemizing 9: AnnProcDemo.java

import java.lang.mirror.Methodology;

public class AnnProcDemo
{
   public static void predominant(String[] args) throws Exception
   {
      if (args.size != 1)
      {
         System.err.println("utilization: java AnnProcDemo classfile");
         return;
      }
      Methodology[] strategies = Class.forName(args[0]).getMethods();
      for (int i = 0; i < strategies.size; i++)
      {
         if (strategies[i].isAnnotationPresent(ToDo.class))
         {
            ToDo todo = strategies[i].getAnnotation(ToDo.class);
            String[] elements = todo.worth().break up(",");
            System.out.printf("ID = %spercentn", elements[0]);
            System.out.printf("End date = %spercentn", elements[1]);
            System.out.printf("Coder = %spercentnpercentn", elements[2]);
         }
      }
   }
}

After verifying that precisely one command-line argument (figuring out a category file) has been specified, predominant() hundreds the category file through Class.forName(), invokes getMethods() to return an array of java.lang.mirror.Methodology objects figuring out all public strategies within the class file, and processes these strategies.

Methodology processing begins by invoking Methodology’s boolean isAnnotationPresent(Class<? extends
Annotation> annotationClass)
technique to find out if the annotation described by ToDo.class is current on the strategy. In that case, Methodology’s <T extends Annotation> T getAnnotation(Class<T>
annotationClass)
technique is named to acquire the annotation.

The ToDo annotations which can be processed are these whose sorts declare a single String worth() aspect (see Itemizing 5). As a result of this aspect’s string-based metadata is comma-separated, it must be break up into an array of element values. Every of the three element values is then accessed and output.

Compile this supply code (javac AnnProcDemo.java). Earlier than you’ll be able to run the appliance, you’ll want an appropriate class file with @ToDo annotations on its public strategies. For instance, you would modify Itemizing 6’s AnnDemo supply code to incorporate public in its type() and search() technique headers. You’ll additionally want Itemizing 10’s ToDo annotation kind, which requires the RUNTIME retention coverage.

Itemizing 10: ToDo.java (model 4)

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

@Goal({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ToDo
{
   String worth();
}

Compile the modified AnnDemo.java and Itemizing 10, and execute the next command to course of AnnDemo’s ToDo annotations:

java AnnProcDemo AnnDemo

If all goes nicely, it’s best to observe the next output:

ID = 1000
End date = 10/10/2019
Coder = John Doe

ID = 1000
End date = 10/10/2019
Coder = John Doe

Commonplace annotation sorts

Together with Goal, Retention, Documented, and Inherited, Java 5 launched java.lang.Deprecated, java.lang.Override, and java.lang.SuppressWarnings. These three annotation sorts are designed for use in a compiler context solely, which is why their retention insurance policies are set to SOURCE.

Deprecated



Supply hyperlink

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles