Java Custom Annotations Example

  • 26 July 2018
  • ADM

 

Java Custom Annotations Example - images/logos/java.jpg

 

Annotations in Java provide information about the code. Java annotations have no direct effect on the code they annotate but can be used to provide info where the code is being used.

Predefined Annotations in Java

Java Provides some built-in annotations:

@Deprecated - indicates that the marked element is deprecated and should no longer be used.

@Override - informs the compiler that the element is meant to override an element declared in a superclass.

@SuppressWarnings - tells the compiler to suppress specific warnings that it would otherwise generate.

@SafeVarargs - when applied to a method or constructor, asserts that the code does not perform potentially unsafe operations on its varargs parameter.

@FunctionalInterface - indicates that the type declaration is intended to be a functional interface.

Annotations that applied to other annotations:

@Retention - annotation specifies how the marked annotation is stored:

  • RetentionPolicy.SOURCE - The marked annotation is retained only in the source level and is ignored by the compiler.
  • RetentionPolicy.CLASS - The marked annotation is retained by the compiler at compile time, but is ignored by the Java Virtual Machine (JVM).
  • RetentionPolicy.RUNTIME - The marked annotation is retained by the JVM so it can be used by the runtime environment.

@Documented -annotation indicates that whenever the specified annotation is used those elements should be documented using the Javadoc tool.

@Target - annotation marks another annotation to restrict what kind of Java elements the annotation can be applied to:

  • ElementType.ANNOTATION_TYPE can be applied to an annotation type.
  • ElementType.CONSTRUCTOR can be applied to a constructor.
  • ElementType.FIELD can be applied to a field or property.
  • ElementType.LOCAL_VARIABLE can be applied to a local variable.
  • ElementType.METHOD can be applied to a method-level annotation.
  • ElementType.PACKAGE can be applied to a package declaration.
  • ElementType.PARAMETER can be applied to the parameters of a method.
  • ElementType.TYPE can be applied to any element of a class.

@Inherited - annotation indicates that the annotation type can be inherited from the super-class.

@Repeatable - indicates that the marked annotation can be applied more than once to the same declaration or type use.

Custom Annotations

Creating a custom annotation in Java is similar to writing an interface, except that it interface keyword is prefixed with @ symbol.

Code

The example below is designed to be used for a field and the retention is set up to RUNTIME, otherwise, the usage example wouldn't work.

package com.admfactory.annotation;

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

@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface DBField {
    String name();

    Class< ?> type();

    boolean isPrimaryKey() default false;
}

Usage

Annotated class:

package com.admfactory.annotation;

import java.util.Date;

public class User {

    @DBField(name = "id", isPrimaryKey = true, type = Long.class)
    private long id;

    @DBField(name = "name", type = String.class)
    private String name;

    @DBField(name = "email", type = String.class)
    private String email;

    @DBField(name = "created", type = Date.class)
    private Date created;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }
}

Getting info from an object of an annotated class type using reflection:

package com.admfactory.annotation;

import java.lang.reflect.Field;
import java.util.Date;

public class AnnotationExample {

    public static void main(String[] args) throws Exception {
        System.out.println("Java Custom Annotation Example");
        System.out.println();

        User usr = new User();
        usr.setEmail("john.doe@example.com");
        usr.setName("John Doe");
        usr.setId(112);
        usr.setCreated(new Date());

        for (Field field : usr.getClass().getDeclaredFields()) {
            DBField dbField = field.getAnnotation(DBField.class);
            System.out.println("field name: " + dbField.name());

            /** changed the access to public */
            field.setAccessible(true);
            Object value = field.get(usr);
            System.out.println("field value: " + value);

            System.out.println("field type: " + dbField.type());
            System.out.println("is primary: " + dbField.isPrimaryKey());
            System.out.println();
        }
    }
}

Output

Java Custom Annotation Example

field name: id
field value: 112
field type: class java.lang.Long
is primary: true

field name: name
field value: John Doe
field type: class java.lang.String
is primary: false

field name: email
field value: john.doe@example.com
field type: class java.lang.String
is primary: false

field name: created
field value: Wed Jul 25 17:10:05 BST 2018
field type: class java.util.Date
is primary: false

 

References