Java Iterator

×

Iterator without Generics Example

Overview

  • Note: Using Raw Type Member of Collections may throw an compiler Warning
  • Workaround: Use Genrics

Java Code

import java.util.ArrayList;
import java.util.Iterator;
 
public class IteratorDemo1 {
 
  public static void main(String args[]){
    ArrayList names = new ArrayList();
    names.add("Chaitanya");
    names.add("Steve");
    names.add("Jack");
 
    Iterator it = names.iterator();
 
    while(it.hasNext()) {
      String obj = (String)it.next();
      System.out.println(obj);
    }
  }
}

Compiler Warnings

D:\JAVA\tutorial\Iterator> javac IteratorDemo1.java
Note: IteratorDemo1.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

D:\JAVA\tutorial\Iterator> javac -Xlint:unchecked IteratorDemo1.java
IteratorDemo1.java:8: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
    names.add("Chaitanya");
             ^
  where E is a type-variable:
    E extends Object declared in class ArrayList
IteratorDemo1.java:9: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
    names.add("Steve");
             ^
  where E is a type-variable:
    E extends Object declared in class ArrayList
IteratorDemo1.java:10: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
    names.add("Jack");
             ^
  where E is a type-variable:
    E extends Object declared in class ArrayList
3 warnings

Output

D:\JAVA\tutorial\Iterator> java IteratorDemo1
Chaitanya
Steve
Jack

Iterator Example throwing a ClassCastException during Runtine

  • IteratorDemo2.java throws a Runtime Exception java.lang.ClassCastException – this should be avoided !

Java Code

import java.util.ArrayList;
import java.util.Iterator;
 
public class IteratorDemo2 {
 
  public static void main(String args[]){
    ArrayList names = new ArrayList();
    names.add("Chaitanya");
    names.add("Steve");
    names.add("Jack");
    
    //Adding Integer value to String ArrayList
    names.add(new Integer(10));
 
    Iterator it = names.iterator();
 
    while(it.hasNext()) {
      String obj = (String)it.next();
      System.out.println(obj);
    }
  }
}

Compiler Warnings

D:\JAVA\tutorial\Iterator> javac IteratorDemo2.java
Note: IteratorDemo2.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Output

D:\JAVA\tutorial\Iterator> java IteratorDemo2
Chaitanya
Steve
Jack
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        at IteratorDemo2.main(IteratorDemo2.java:18)

Iterator sample using Generics throwing a Compile Error

  • This sample throws Compiler Error: no suitable method found for add(Integer)

Java Code

import java.util.ArrayList;
import java.util.Iterator;
 
public class IteratorDemo4 {
  public static void main(String args[]){
    ArrayList names = new ArrayList();
    names.add("Chaitanya");
    names.add("Steve");
    names.add("Jack");
    names.add(new Integer(10)); 
    
    Iterator it = names.iterator();
 
    while(it.hasNext()) {
      String obj = it.next();
      System.out.println(obj);
    }
 }
}

Compiler Error

D:\JAVA\tutorial\Iterator> javac IteratorDemo4.java
IteratorDemo4.java:10: error: no suitable method found for add(Integer)
    names.add(new Integer(10));
         ^
    method Collection.add(String) is not applicable
      (argument mismatch; Integer cannot be converted to String)
    method List.add(String) is not applicable
      (argument mismatch; Integer cannot be converted to String)
    method AbstractCollection.add(String) is not applicable
      (argument mismatch; Integer cannot be converted to String)
    method AbstractList.add(String) is not applicable
      (argument mismatch; Integer cannot be converted to String)
    method ArrayList.add(String) is not applicable
      (argument mismatch; Integer cannot be converted to String)
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

Fix Compiler Error and run Sample

Java Code

import java.util.ArrayList;
import java.util.Iterator;
 
public class IteratorDemo3 {
  public static void main(String args[]){
    ArrayList names = new ArrayList();
    names.add("Chaitanya");
    names.add("Steve");
    names.add("Jack");
 
    Iterator it = names.iterator();
 
    while(it.hasNext()) {
      String obj = it.next();
      System.out.println(obj);
    }
 }
}

No Compiler Warnings/errors

D:\JAVA\tutorial\Iterator> javac IteratorDemo3.java

Output

D:\JAVA\tutorial\Iterator> java IteratorDemo3
Chaitanya
Steve
Jack

Reference

Why using a Nested Class ?

  • It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such “helper classes” makes their package more streamlined.
  • It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A’s members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.
  • It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.

Java Sample

package animals;
public class Animals {
    /**
     * @param args the command line arguments
     */
    public String type = "Animal"; 
    static Animals.Alpaca alpaca; 
    static Animals.Llama llama;
    
    public static void main(String[] args) {
        alpaca = new Animals.Alpaca(); // new Alpaca is created
        llama = new Animals.Llama(); // new Llama is created
        Animals animals = new Animals();
        alpaca.getDetailsAlpaca(animals);
        llama.getDetailsLlama(animals);
    }
    public static class Alpaca {
        private final String name;
        public Alpaca() {
            name = "Alpaca";
            System.out.println(name + " is born! " );
        }
        public void getDetailsAlpaca(Animals animals) {
            System.out.println("This is an " + name + ". I am an " + animals.type + " !" );
        } 
    }     
    public static class Llama {
        private final String name;
        public Llama() {
            name = "Llama";
            System.out.println(name + " is born! " );
        }
        public void getDetailsLlama(Animals animals) {
            System.out.println("This is a " + name + ". I am an " + animals.type + " too !"  );
        }    
    }
          
    public Animals() {
        System.out.println("Animals constructor");
    }
}

Output Java Sample

Alpaca is born! 
Llama is born! 
Animals constructor
This is an Alpaca. I am an Animal !
This is a Llama. I am an Animal too !

Grouping Details

  • At their core, static classes exist to allow you to group classes together
  • If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together
  • Java doesn’t allow you to create top-level (non-nested) static classes, so static classes will always be nested.

Instantiation Details

  • Referring to the sample code above, the important distinction to make is that
  • Creating an Animals object does not create an Alpaca or Llama object.
  • To instantiate the nested static class, we have to use new on the Animals class itself .
  • The nested static class Alpaca acts like its own class, but the only thing is, it must be accessed via the Animals top-level class
  • An instance of the top-level class is not needed to create an object of the nested class.

Level of access Details

  • Nested static classes are able to access static data members of the top-level class (and call static methods)
  • Nested static classes are unable to access non-static data members since you can create an instance of a static inner class without creating any instance of the outer class.
  • A static nested class interacts with the instance members of its outer class just like any other top-level class.

Reference

JUNIT and Java

×

Overview Versions

  • Netbeans 8.2
  • JUNIT 4
  • JUNIT uses Java Reflection API to run Object Methods

Java IO sample

package fileio;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FileIO {
    private static final Logger LOGGER = Logger.getLogger( 
            Thread.currentThread().getStackTrace()[0].getClassName() );
    
    /** FileOutputStream Descriptor */        
    private FileOutputStream fos = null;
    /** OS-FileName */
    final private String fileName ;
    public FileOutputStream getFileOutputStream() { return fos; }
    public String getFileName() { return fileName; }
    
    public static void main(String[] args) {
        String writeContent = "This is my Data which needs" +
	        " to be written into the file";
        String fileName = "C:/myfile.txt";
        //LOGGER.setLevel(Level.FINEST);
        //LOGGER.setLevel(Level.SEVERE);              
        LOGGER.setLevel(Level.INFO);                  // Setting current Logger Level
        
        Locale.setDefault(new Locale("en", "EN"));  // Change Logger Language to English 
        FileIO fileIO = new FileIO(fileName);
        fileIO.doIO(fileName, writeContent);
    }
       
    public FileIO(String fileName) {
        this.fileName = fileName;
        LOGGER.info("FileIO constructor for fileName: " + fileName);
    }
/**
 * Opens, writes and closes FileOutputStream fos.
 * 

* If open was successfull both fileName and FileOutputStream Object are * stored in the related class attributes fileName, fos for later access * @param fName The fileName at OS Level * @param writeContent The message to be written to our FileOutputStream * @return true If write was successfull else return false */ public boolean doIO(String fName,String writeContent) { try { openStream(fName); // Got an excpetion if open failse int bytesWritten = writeToStream( writeContent); boolean ret = closeStream(); String loggerString = new StringBuilder("Byte written to File ") .append( this.fileName ).append(": " ).append(bytesWritten).toString(); LOGGER.info(loggerString); return true; } catch ( IOException ioe) { // Only log the Exception Message - stacktrace should be printed by low level // Exception handler. Close the stream when there is am Exception ! LOGGER.log( Level.SEVERE, ioe.toString() ); return false; } finally{ closeStream(); } } /** * Opens a FileOutputStream fos. *

* If open was successfull both fileName and FileOutputStream Object are * stored in the related class attributes fileName, fos for later access * @param fileName The fileName at OS Level * @throws IOException If stream can't be opened at OS level * @return true If Stream was opened sucessfully */ public boolean openStream (String fileName) throws IOException { String fName = fileName; FileOutputStream lfos; File file; try { if ( fName == null ) { throw new IOException("fileName can't be null"); } //Specify the file path here file = new File(fileName); lfos = new FileOutputStream(file); /* This logic will check whether the file exists or not. If the file * is not found at the specified location it would createa new file */ if (!file.exists()) { file.createNewFile(); } this.fos = lfos; // save the FileOutputStream Descriptor for later usage return true; } catch ( IOException ioe) { String errorMesg = "Error open File-Stream " + fileName; LOGGER.log( Level.SEVERE, ioe.toString(), ioe ); this.fos = null; throw new IOException(errorMesg); } } /** * Writes a String Message to already opened FileOutputStream fos. *

* Note: This methode will convert a potenial NullPointerExceptions tiggered * by either message=null or FileOutputStream fos=null to an IOExeption. * @param message The String to be written to the Stream Descriptor fos * @throws IOException If stream is not already opened at OS level or If messsage is null * @return byteCnt The number of bytes written to our opened Stream */ public int writeToStream( String message) throws IOException { try { /*String content cannot be directly written into * a file. It needs to be converted into bytes */ if (message == null ) { throw new IOException("Message should NOT be null ! "); } // don't need to check for null ! if (!(fos instanceof FileOutputStream)) { throw new IOException("FileOutputStream fos should NOT be null ! "); } byte[] bytesArray = message.getBytes(); int byteCnt = bytesArray.length; fos.write(bytesArray); fos.flush(); String loggerString = new StringBuilder("Successfully written " ) .append( byteCnt ).append(" Bytes to File: ").append(fileName).toString(); LOGGER.info(loggerString); return byteCnt; } catch (IOException ioe) { String errorMesg = "Error writing to File: " + fileName + "\n " + ioe.toString(); LOGGER.log( Level.SEVERE, ioe.toString(), ioe ); throw new IOException(errorMesg); } } /** * Closes FileOutputStream fos. *

* Note: Closing an alreday closed FileOutputStream will not throw any error * Even we get an error during close operation closeStream() methode will only log an error * without re-throwing the underlying Exception. * @return true if Stream was closed successfully */ public boolean closeStream() { try { if (fos != null) { fos.close(); } fos = null; return true; } catch (IOException ioe) { String errorMesg = "Error closing Stream " + fileName; LOGGER.log( Level.SEVERE, ioe.toString(), ioe ); return false; } } }

JUnit test for above IO sample

  • Create JUNIT test with Netbeans 8.2: Right Click on Java File -> Tools -> Create/Update Tests


    @AfterClass
    public static void tearDownClass() {
    }
    
    @Before
    public void setUp() {
         String fName = "c:/myFileTest";
        instance = new FileIO(fName);
    }
    
    @After
    public void tearDown() {
    }

    /**
     * Test of main method, of class FileIO.
     */
    @Test
    public void testMain() {
        System.out.println("-> Start Test main()");
        String[] args = null;
        FileIO.main(args);
        System.out.println("   Test main() OK");
    }

    /**
     * Test of openStream method, of class FileIO.
     */
    @Test
    public void testOpenStream() {
        System.out.println("-> Start Test openStream()");
        String fName = "c:/myFileTest";
        boolean result = false;
        // FileIO instance = new FileIO();
        boolean expResult = true;
        try {
            result = instance.openStream(fName);
        } catch ( IOException iex) {}
        
        assertTrue("Expected Test Result " + expResult +  " - Got: " +  result,  expResult==result);
        System.out.println("   Test openStream() OK!");
    }
    
       /*
        *  Open a Non-Existing File - Should fail with an IOException    
        */
    @Test (expected=IOException.class)
    public void testOpenStreamFailed() throws IOException{
        System.out.println("-> Start Test testOpenStreamFailed() - Fails with an IOException !");
        String fName = "X:/myFileTestFailed";
        boolean result = false;
        FileOutputStream expResult = null;
        result = instance.openStream(fName);
    }
    
    /**
     * Test of writeToStream method, of class FileIO.
     */
    @Test 
    public void testWriteToStream() {
        String fName = "c:/myFileTest";
        FileOutputStream fos;
        int bytesWritten = 0;
        System.out.println("-> Start Test writeToStream()");
        String message = "This is just a Test";
        int bytesToBeWritten = message.getBytes().length ;
        try {
            instance.openStream(fName);
            bytesWritten = instance.writeToStream(message);
        } catch ( IOException iex) {}
        assertTrue("Error::  Expected bytesToBeWritten: " +  bytesToBeWritten 
                + " - GOT bytesWritten " + bytesWritten ,bytesWritten == bytesToBeWritten );
        System.out.println("   Test writeToStream() OK! - bytesWritten: " + bytesWritten);

    }

    /*
        In this test we simulate a write to a Not initialized Stream Desriptor
        This Test should fail with an IOExecption     
    */
    @Test (expected=IOException.class)
    public void testWriteToStreamFailed() throws IOException {
        String fName = "c:/myFileTest";
        FileOutputStream fos = null;

        System.out.println("-> Start testWriteToStreamFailed() - Fails with IOException !");
        String message = "This is just a Test";
        int bytesToBeWritten = message.getBytes().length ;
        // instance.writeToStream should trigger an IOException
        int bytesWritten = instance.writeToStream( message);
    }
    
    /**
     * Test of closeStream method, of class FileIO.
     * We also test that closing a closed Stream doesn't throw any Exception lile in socket opes
     */
    @Test
    public void testCloseStream() {
        String fName = "c:/myFileTest";
        FileOutputStream fos = null;
        System.out.println("-> Start Test closeStream()");
        String message = "This is just a Test";
        boolean result = false;
         
        // FileIO instance = new FileIO();
        try {
            instance.openStream(fName);
            result = instance.closeStream();
          } catch ( IOException iex) {}
        assertTrue("Error: Expected true in first close !", result);
            // Now closing an alreay closed Stream
        result = instance.closeStream();
        assertTrue("Error: Expected true in 2.nd close !", result);
        System.out.println("   Test closeStream() - 2.nd Close OK No Exception !" +
            " - ret Status: " + result );
    }

    /**
     * Test of doIO method, of class FileIO.
     * Should Work and return true !
     */
    @Test
    public void testDoIO() {
        System.out.println("-> Start Test doIO()");
        String fName = "c:/myFileTest";
         String writeContent = "This is my Data which needs" +
	        " to be written into the file";
        //FileIO instance = new FileIO();
        boolean result = instance.doIO(fName,writeContent);
        assertTrue("Error: Expected true !", result);
        System.out.println("   Test doIO() OK - result " + result );
    }    
    
    /**
     * Test of doIO method, of class FileIO. 
     * This test is the most important ONE as we will test that a failed Write closes fos 
     * descriptor to avoid a resource leak. To test this does we issue an add. write after calling 
     * doIO(). This add write should fail indicating that fos descriptor was already closed
     * TestString : null
     *              -> doIO() should return false but close fos
     *              -> An addition Write Test using the closed fos shoud fail too   
     */

    @Test
    public void testDoIOFailed() throws IOException {
        System.out.println("-> Start Test testDoIOFailed() - Fails with an Assert !");
        String fName = "c:/myFileTest";
        String writeContent = null;
        //FileIO instance = new FileIO();
        boolean result = instance.doIO(fName,writeContent);
        assertFalse("Error: Expected false !", result);
            // As we can get the Stream closed status form FileOutputStream object we start a test
            // write. Note: 
            // After a failure the Stream should be closed - we expect the the next write to fail !
        writeContent = "This WRITE should NOT Work";
        int bytesToBeWritten = writeContent.getBytes().length;
        int bytesWritten = -1;
        try {
            bytesWritten = instance.writeToStream( writeContent);
        } catch ( IOException e) {}
        assertFalse("This Write should fail - as the FOS descpriptor should be closed before!", bytesToBeWritten == bytesWritten );
    }    
    
    /* 
        Writing a null Message should reurn an IOException and Not a java.lang.NullPointerException 
    */
    @Test
    public void testWriteFailed() throws IOException{
        String fName = "c:/myFileTest";
        FileOutputStream fd;
        String message = null;
        int bytesToBeWritten = -1;
        int bytesWritten = -1;
        System.out.println("-> Start Test testWriteFailed() - Catches IOException !");
       
        instance.openStream(fName);
        fd = instance.getFileOutputStream();
        assertTrue(fd instanceof FileOutputStream);
     
        try {
            bytesWritten = instance.writeToStream( message);
        } catch ( IOException iex) {} 
        
        //  This Test raises an java.io.IOException: Message should NOT be null at all -
        // > bytesWritten remain unchanged 
        assertTrue("Error::  Expected bytesToBeWritten: " +  bytesToBeWritten 
                + " - GOT bytesWritten " + bytesWritten ,bytesWritten == bytesToBeWritten );
 
        boolean closeResult = instance.closeStream();
        assertTrue("Error: Expected true !", closeResult);       
        System.out.println("   Test testWriteFailed()  OK "  );
    }    
}

JUNIT Test Output

-> Start Test writeToStream()
   Test writeToStream() OK! - bytesWritten: 19
-> Start testWriteToStreamFailed() - Fails with IOException !
-> Start Test doIO()
   Test doIO() OK - result true
-> Start Test main()
   Test main() OK
-> Start Test closeStream()
   Test closeStream() - 2.nd Close OK No Exception ! - ret Status: true
-> Start Test openStream()
   Test openStream() OK!
-> Start Test testDoIOFailed() - Fails with an Assert !
-> Start Test testWriteFailed() - Catches IOException !
   Test testWriteFailed()  OK 
-> Start Test testOpenStreamFailed() - Fails with an IOException !
Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO writeToStream
INFORMATION: Successfully written 19 Bytes to File: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SCHWERWIEGEND: java.io.IOException: FileOutputStream fos should NOT be null ! 
java.io.IOException: FileOutputStream fos should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:122)
	at fileio.FileIOTest.testWriteToStreamFailed(FileIOTest.java:114)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...

Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO writeToStream
INFORMATION: Successfully written 55 Bytes to File: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO doIO
INFORMATION: Byte written to File  c:/myFileTest: 55
Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: C:/myfile.txt
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
INFO: Successfully written 55 Bytes to File: C:/myfile.txt
Mar 30, 2018 1:52:42 PM fileio.FileIO doIO
INFO: Byte written to File  C:/myfile.txt: 55
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SEVERE: java.io.IOException: Message should NOT be null ! 
java.io.IOException: Message should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:119)
	at fileio.FileIO.doIO(FileIO.java:51)
	at fileio.FileIOTest.testDoIOFailed(FileIOTest.java:173)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...

Mar 30, 2018 1:52:42 PM fileio.FileIO doIO
SEVERE: java.io.IOException: Error writing to File: c:/myFileTest
  java.io.IOException: Message should NOT be null ! 
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SEVERE: java.io.IOException: FileOutputStream fos should NOT be null ! 
java.io.IOException: FileOutputStream fos should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:122)
	at fileio.FileIOTest.testDoIOFailed(FileIOTest.java:182)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	..

Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SEVERE: java.io.IOException: Message should NOT be null ! 
java.io.IOException: Message should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:119)
	at fileio.FileIOTest.testWriteFailed(FileIOTest.java:204)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...

Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO openStream
SEVERE: java.io.FileNotFoundException: X:\myFileTestFailed (Das System kann den angegebenen Pfad nicht finden)
java.io.FileNotFoundException: X:\myFileTestFailed (Das System kann den angegebenen Pfad nicht finden)
	at java.io.FileOutputStream.open0(Native Method)
	at java.io.FileOutputStream.open(FileOutputStream.java:270)
	at java.io.FileOutputStream.(FileOutputStream.java:213)
	at java.io.FileOutputStream.(FileOutputStream.java:162)
	at fileio.FileIO.openStream(FileIO.java:87)
	at fileio.FileIOTest.testOpenStreamFailed(FileIOTest.java:77)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...

Java Tutorial: Annotation and Reflection

Annotation and Reflection

  • Annotations have a number of uses, among them:
    • Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings.
    •   Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
    •   Runtime processing — Some annotations are available to be examined at runtime.
  • Annotation type declarations are similar to normal interface declarations.
  • An at-sign (@) precedes the interface keyword – Sample : public @interface ClassInfo
  • The annotations are not method calls and will not, by themselves, do anything.  Rather any tool like JPA need to extract the annotations at runtime and need to do execute the designed action like: Generating an object-relational mapping.
  • Following JAVA language constructs can be annotated: Class, Constructor, Field, Method, and Package
  • The Java compiler conditionally stores annotation metadata in the class files if the annotation has a RetentionPolicy of CLASS or RUNTIME. Later, the JVM or other programs can look for the metadata to determine how to interact with the program elements or change their behavior [ via Reflection API ]
  • Annotation can  also  be used to provide some info about who change a component [ Java Class , Java Methode ]

Custom Annotations Details for Runtime processing with Reflection

ClassInfo - @Target(value = ElementType.TYPE) 
  - Provide some Info who has changed a certain specific JAVA source
  - Use reflection code below to display the Anotation Info
     if(annotation instanceof ClassInfo)
     {
         ClassInfo myAnnotation = (ClassInfo) annotation;
         System.out.println(" -> autor           : " + myAnnotation.author());
         System.out.println(" -> date            : " + myAnnotation.date());
         System.out.println(" -> comment         : " + myAnnotation.comments());
     }

CanRun - @Target(value = ElementType.METHOD) 
   - Indicate that we can/should run a certain JAVA methode via reflection
   - Run that specific methode by using reflection code:  
         method.invoke(runner);

CanChange - @Target(value = ElementType.FIELD)  
   - Indicate that we can/should modify a certain JAVA methode via reflection 
   - Change a int field  by using reflection code:  
        f.setInt(runner,k);
 
CanConstruct - @Target(value = ElementType.CONSTRUCTOR) 
   - Indicates that we can/should run a certain JAVA Constructor via reflection
   - Construct a new AnnotationRunner instance and printout the int field id1  by using reflection code: 
       ctor.setAccessible(true);
       AnnotationRunner  r = (AnnotationRunner)ctor.newInstance();
       Field f = r.getClass().getDeclaredField("id1");
       f.setAccessible(true); 

Note all of the above Anotations are used during Runtime and thus  
@Retention(value = RetentionPolicy.RUNTIME) is mandatory

Java source: ClassInfo.java

package utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface ClassInfo 
{
    String author() default "Helmut";
    String date();
    String comments();
}

Java source: CanChange.java

package utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface CanChange 
    {
    }

Java source: CanRun.java

package utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface CanRun {
}

Java source: CanConstruct.java

package utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.CONSTRUCTOR)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface CanConstruct
    {
    }

Java source – The helper class: ReflectionUtils.java

package utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * Die Klasse <code>ReflectionUtils</code> ist eine Utility-Klasse, die
 * verschiedene Hilfsmethoden zur vereinfachten Handhabung von Reflection
 * bereitstellt.
 * 
* @author Michael Inden
 * 
* Copyright 2011 by Michael Inden
 */
public final class ReflectionUtils
    {

    public static String modifierToString(final int modifier)
      {
        String modifiers = "";
        if (Modifier.isPublic(modifier))
          {
            modifiers += "public ";
          }
        if (Modifier.isProtected(modifier))
          {
            modifiers += "protected ";
          }
        if (Modifier.isPrivate(modifier))
          {
            modifiers += "private ";
          }
        if (Modifier.isStatic(modifier))
          {
            modifiers += "static ";
          }
        if (Modifier.isAbstract(modifier))
          {
            modifiers += "abstract ";
          }
        if (Modifier.isFinal(modifier))
          {
            modifiers += "final ";
          }
        if (Modifier.isVolatile(modifier))
          {
            modifiers += "volatile ";
          }
        if (Modifier.isSynchronized(modifier))
          {
            modifiers += "synchronized ";
          }
        return modifiers;
      }

    public static Field findField(final Class<?> clazz, final String fieldName)
      {
// Abbruch der Rekursion
        if (clazz == null)
          {
            return null;
          }
        try
          {
            return clazz.getDeclaredField(fieldName);
          } catch (final NoSuchFieldException ex)
          {
// rekursive Suche in Superklasse
            return findField(clazz.getSuperclass(), fieldName);
          }
      }

    public static Method findMethod(final Class<?> clazz, final String methodName, final Class<?>... parameterTypes)
      {
// Abbruch der Rekursion
        if (clazz == null)
          {
            return null;
          }
        try
          {
            return clazz.getDeclaredMethod(methodName, parameterTypes);
          } catch (final NoSuchMethodException ex)
          {
// rekursive Suche in Superklasse
            return findMethod(clazz.getSuperclass(), methodName, parameterTypes);
          }
      }

    
   public static Method[] getAllMethods(final Class<?> clazz)
      {
        final List<Method> methods = new ArrayList<Method>();
        methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
        /*
        if (clazz.getSuperclass() != null)
          {
              // rekursive Suche in Superklasse
            methods.addAll(Arrays.asList(getAllMethods(clazz.getSuperclass())));
          }
                */
        return methods.toArray(new Method[0]);
      }
       
    public static Field[] getAllFields(final Class<?> clazz)
      {
        final List<Field> fields = new ArrayList<Field>();
        //   Field[] fields = cls.getDeclaredFields();
        fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
       
        return fields.toArray(new Field[0]);
      }
    
     public static Constructor[] getAllConstructors(final Class<?> clazz)
      {
        final List<Constructor> constructors = new ArrayList<Constructor>();
        //   Field[] fields = cls.getDeclaredFields();
        constructors.addAll(Arrays.asList(clazz.getConstructors()));
        return constructors.toArray(new Constructor[0]);
      }
    
    public static void printCtorInfos(final Constructor<?> ctor)
      {
        System.out.println(modifierToString(ctor.getModifiers()) + " " + ctor.getName()
                + buildParameterTypeString(ctor.getParameterTypes()));
        printAnnotations(ctor.getAnnotations());
      }

    public static void printMethodInfos(final Method method)
      {
        System.out.println(modifierToString(method.getModifiers()) + method.getReturnType() + " " + method.getName()
                + buildParameterTypeString(method.getParameterTypes()));
        printAnnotations(method.getAnnotations());
      }

    public static void printFieldInfos(final Field field)
      {
        System.out.println(ReflectionUtils.modifierToString(field.getModifiers()) + field.getType() + " "
                + field.getName());
        printAnnotations(field.getAnnotations());
      }

    public static String buildParameterTypeString(final Class<?>[] parameterTypes)
      {
        if (parameterTypes.length > 0)
          {
            return "(" + Arrays.toString(parameterTypes) + ")";
          }
        return "()";
      }

    private static void printAnnotations(final Annotation[] annotations)
      {
        if (annotations.length > 0)
          {
            System.out.println("Annotations: " + Arrays.toString(annotations));
          }
      }
    
    public static void printClassInfo(final Class<?> clazz )
      {
        // System.out.println("Canonical Class Name: " + clazz.getCanonicalName() );
        System.out.println("Class Name          : "  + clazz.getName() ); 
        System.out.println("Superclass Name     : "  + clazz.getSuperclass() ); 
        System.out.println("Interfaces          : "  + Arrays.toString(clazz.getInterfaces())); 
      //  Class c  = runner.getClass();
        Annotation[] annotations = clazz.getAnnotations();
         for(Annotation annotation : annotations)
           {
           if(annotation instanceof ClassInfo)
              {
              ClassInfo myAnnotation = (ClassInfo) annotation;
              System.out.println(" -> autor           : " + myAnnotation.author());
              System.out.println(" -> date            : " + myAnnotation.date());
              System.out.println(" -> comment         : " + myAnnotation.comments());
              }
           }
      }
            
    private ReflectionUtils()
      {
      }
    }

Java source: AnnotationRunner.java

package AnnotationTest;
import utils.CanChange;
import utils.CanRun;
import utils.CanConstruct;
import utils.ClassInfo;

@ClassInfo( author="Helmut Hutzer", 
            date="8-Feb-2014",
            comments="Intial Class Creation for Testing annotations" )
public class AnnotationRunner {
    @CanChange
    public int id1 = 1;
    public int id2= 2;
    
    @CanConstruct
    public AnnotationRunner()
        {
        }
    
    public AnnotationRunner(int v_id1, int v_id2)
    {
        id1 = v_id1;
        id2 = v_id2;
    }
    
    public void method1() 
    {
        System.out.println("Hello from method1 : " + id1);
    }

    @CanRun
    public void method2() 
    {
        System.out.println("Hello from method2 !");
    }
    
    public void set_id1(int v_id) 
    {
        id1 = v_id;
    }
    
    public void set_id2(int v_id) 
    {
        id2 = v_id;
    }
}

Java source: MyTest.java

package AnnotationTest;

import java.lang.annotation.Annotation;
import utils.CanChange;
import utils.CanRun;
import utils.CanConstruct;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class MyTest 
{
    public static void main(String[] args) 
    {
        AnnotationRunner runner = new AnnotationRunner();     
        
        System.out.println("\n-->Inspect Class:");
        utils.ReflectionUtils.printClassInfo( runner.getClass());
        
          System.out.println("\n-->Inspect Class:");
        utils.ReflectionUtils.printClassInfo(CanChange.class);
        
        System.out.println("\n--> Exploring Constructors  ");
        Constructor[] constructors =  utils.ReflectionUtils.getAllConstructors(runner.getClass());
        Constructor ctor =null;
        for (  Constructor  constructor : constructors) 
        {
            utils.ReflectionUtils.printCtorInfos(constructor);
                // Find the constructor without any paramter
            if (constructor.getGenericParameterTypes().length == 0)
                ctor = constructor;
        } 
        
          // See ; http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html 
        
        if ( ctor != null )
        {
            System.out.println("--> Found a constructor without parameters ");
            Annotation annos = ctor.getAnnotation(CanConstruct.class);
            if (annos != null) 
            {
                try
                {
                    System.out.println("--> Found Annotation CanConstruct   ");
                    utils.ReflectionUtils.printCtorInfos(ctor);
                    ctor.setAccessible(true);
                    AnnotationRunner  r = (AnnotationRunner)ctor.newInstance();
                    Field f = r.getClass().getDeclaredField("id1");
                    f.setAccessible(true);
                    System.out.println("--> Created new instance of class  AnnotationRunner");
                    System.out.println("--> print Field id1 via reflecion : "+   f.get(r));
                } catch ( InstantiationException | IllegalAccessException 
                            | NoSuchFieldException | InvocationTargetException ex ) 
                     { ex.printStackTrace(); }
            }
        }
        
        System.out.println("\n --> Exploring method annotations ");
         // utils.ReflectionUtils.getAllMethods scans your superclass too !
        Method[] methods =  utils.ReflectionUtils.getAllMethods(runner.getClass());
        
        for (Method method : methods) 
          {
            utils.ReflectionUtils.printMethodInfos(method);
            Annotation annos = method.getAnnotation(CanRun.class);
            if (annos != null) 
            {
                System.out.println("--> Found CanRun.class Annotation for method: " + method.getName() );
                try {
                    System.out.println("--> Invoking this method via reflection ");
                    method.invoke(runner);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            else
              {
              System.out.println("--> Found NO Annotation for method: " + method.getName() );  
              }
          }
//        Field[] fields   = runner.getClass().getFields();
        
        System.out.println("\n --> Exploring Attributes:");
        Field[] fields =  utils.ReflectionUtils.getAllFields(runner.getClass());
        for (Field f : fields) 
        {
            utils.ReflectionUtils.printFieldInfos(f);
            Annotation annos = f.getAnnotation(CanChange.class);
            if (annos != null) 
            {
                System.out.println("--> Found Annotation for field: " + f.getName() + " " + f.getType()  );  
                try 
                {                  
                    if (  f.getType().equals(int.class) )
                    {
                        int k = 99 ;
                        System.out.println("--> Current value for id1 : " + runner.id1 );
                        f.setInt(runner,k);
                        System.out.println("--> Changing int value for attr " +f.getName() + 
                                 " via reflection - New value: " + runner.id1 );
                    }
                } 
                catch (IllegalAccessException ex) 
                {
                    ex.printStackTrace();
                }
            }
        }
    }
} 

Program Output running MyTest.java

-->Inspect Class:
Canonical Class Name: AnnotationTest.AnnotationRunner
Class Name          : AnnotationTest.AnnotationRunner
Superclass Name     : class java.lang.Object
Interfaces          : []
 -> autor           : Helmut Hutzer
 -> date            : 8-Feb-2014
 -> comment         : Intial Class Creation for Testing annotations

-->Inspect Class:
Canonical Class Name: utils.CanChange
Class Name          : utils.CanChange
Superclass Name     : null
Interfaces          : [interface java.lang.annotation.Annotation]

--> Exploring Constructors  
public  AnnotationTest.AnnotationRunner([int, int])
public  AnnotationTest.AnnotationRunner()
Annotations: [@utils.CanConstruct()]
--> Found a constructor without parameters 
--> Found Annotation CanConstruct   
public  AnnotationTest.AnnotationRunner()
Annotations: [@utils.CanConstruct()]
--> Created new instance of class  AnnotationRunner
--> print Field id1 via reflecion : 1

--> Exploring method annotations 
public void method1()
--> Found NO Annotation for method: method1
public void method2()
Annotations: [@utils.CanRun()]
--> Found CanRun.class Annotation for method: method2
--> Invoking this method via reflection 
Hello from method2 !
public void set_id1([int])
--> Found NO Annotation for method: set_id1
public void set_id2([int])
--> Found NO Annotation for method: set_id2

 --> Exploring Attributes:
public int id1
Annotations: [@utils.CanChange()]
--> Found Annotation for field: id1 int
--> Current value for id1 : 1
--> Changing int value for attr id1 via reflection - New value: 99
public int id2

Reference