Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Saturday, April 23, 2016

Unit Testing Log Statements

Sometimes asserting on a log statement might be the only way of validating a method call. One way of asserting log statements is to create a custom appender and attaching it to the logger to capture the logs. log4j-api provides the framework to create a custom appender.

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class CustomAppender extends AbstractAppender {

    private List messages = new ArrayList<>();

    public CustomAppender(String name, Filter filter, Layout layout) {
        super(name, filter, layout);
    }

    public CustomAppender(String name, Filter filter, Layout layout, boolean ignoreExceptions) {
        super(name, filter, layout, ignoreExceptions);
    }

    @Override
    public void append(LogEvent event) {
        byte[] data = getLayout().toByteArray(event);
        messages.add(new String(data).trim()); // optional trim
    }

    @Override
    public void stop() {
        
    }

    public List getMessages() {
        return messages;
    }

}
Following method adds the custom appender to the logger:
private void setUpLogHandler() {
        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        final AbstractConfiguration config = (AbstractConfiguration) ctx.getConfiguration();

        // Create and add the appender
        customAppender = new CustomAppender("Custom", null, PatternLayout.createDefaultLayout());
        customAppender.start();
        config.addAppender(customAppender);

        // Create and add the logger
        AppenderRef[] refs = new AppenderRef[]{AppenderRef.createAppenderRef("Custom", null, null)};
        LoggerConfig loggerConfig = LoggerConfig.createLogger("false", Level.INFO, ClassUnderTest.class.getCanonicalName(), "true", refs, null, config, null);
        loggerConfig.addAppender(customAppender, null, null);
        config.addLogger(ClassUnderTest.class.getCanonicalName(), loggerConfig);
        ctx.updateLoggers();
    }
Below is an example test method which asserts on a method that logs:
    @Test
    public void logTest() {
        setUpLogHandler();
        ClassUnderTest ct = new ClassUnderTest();
        ct.methodThatLogs();
        assertThat(customAppender.getMessages(), hasItem("new log message"));
    }

Wednesday, April 20, 2016

Parameterized JUnit Tests

JUnitParams provides a runner - JUnitParamsRunner, to add parameterized tests in a test class. With this runner parameterized and non-parameterized test methods can be combined in the same class.

@RunWith(JUnitParamsRunner.class)
public class ParameterizedTests {
    @Parameters({"1, true", "2, false"})
    @Test
    public void test1(int num, boolean result) {
        assertThat(num == 1, is(result));
    }
}
To pass in objects or null values, a separate method can be setup, which then can be added to the @Parameters annotation.
@RunWith(JUnitParamsRunner.class)
public class ParameterizedTests {
    private Object[] params() {
        return $(
                $(1, true),
                $(2, false)
        );
    }

    @Parameters(method = "params")
    @Test
    public void test1(int num, boolean result) {
        assertThat(num == 1, is(result));
    }
}

Monday, March 18, 2013

Factory Method Pattern

The Factory Method Pattern encapsulates object creation by letting subclasses decide what objects to create. The creator class defines an abstract factory method that the subclasses implement to produce products. Factory method is known as a creational pattern - it's used to construct objects such that they can be decoupled from the implementing system.

The GoF book on Design Patterns defines it as -
Define an interface for creating an object, but let the subclasses decide which class to instantitate. The Factory method lets a class defer instantiation to subclasses.
In this definition the term "interface" is used in the general sense, meaning - a concrete class implementing a method from a supertype (a class or interface).

The Factory method builds on the concept of a Simple Factory, but lets the sub-classes decide which implementation of the concrete class to use. Simple factory is a programming idiom rather than a pattern, where object creation is relegated to a method. Factory Method pattern builds on it - deferring object creation to sub-classes.

A simple factory can also be defined as a static method and is often called a static factory. This way we don’t have to instantiate an object to make use of the create method. But the disadvantage is that, we can’t subclass and change the behavior of the create method.

Example code from http://java.dzone.com/articles/design-patterns-factory. First an interface and an implementation for the product:

public interface Logger {
	public void log(String message);
}
public class XmlLogger implements Logger {

	@Override
	public void log(String message) {
		System.err.println(message);
	}

}
Creator with the abstract factory method:
public abstract class AbstractLoggerCreator {
	
	//factory method
	public abstract Logger createLogger();
	
	public Logger getLogger() {
		Logger logger = new XmlLogger();
		return logger;
	}
}
Now the concrete creator class:
public class XmlLoggerCreator extends AbstractLoggerCreator {
	@Override
	public Logger createLogger() {
		XmlLogger logger = new XmlLogger();
		return logger;
	}
}
Finally the client code to test the pattern:
public class FactoryMethodClient {
	private void methodA(AbstractLoggerCreator creator) {
		Logger logger = creator.createLogger();
		logger.log("message");
	}

	public static void main(String[] args) {
		AbstractLoggerCreator creator = new XmlLoggerCreator();
		FactoryMethodClient client = new FactoryMethodClient();
		client.methodA(creator);
	}

}
Downside of the pattern is that it might be over-complicated. In a lot of cases, a simple factory pattern will work fine. The FactoryMethod just allows further decoupling, leaving it to the sub-classes of the Creator to decide which type of concrete Product to create.

Thursday, March 07, 2013

Data Structures - Queue

A Queue is an example of a linear data structure - a sequential
collection, and it is a FIFO structure. Anything that's inserted
first, will be the first to leave. We need to maintain two pointers,
the start and the end. An efficient implementation of Queue performs
the operations - enqueue (insert) and dequeue (remove) - in O(1) time.

Below is a sample implementation of a Queue (Java Data Structures (2nd edition))

public class Queue {
 private Object[] objArray;
 private int start, end;
 private boolean full;

 public Queue(final int maxSize) {
  objArray = new Object[maxSize];
  start = end = 0;
  full = false;
 }

 public boolean isEmpty() {
  return (start == end) && !full;
 }

 public boolean isFull() {
  return full;
 }

 public void insert(final Object o) {
  if (!full) {
   objArray[start = (++start % objArray.length)] = o;
  }
  

  if (start == end) {
   full = true;
  }
 }

 public Object remove() {
  if (full) {
   full = false;
  } else if (isEmpty()) {
   return null;
  }

  return objArray[end = (++end % objArray.length)];
 }

 public String toString() {
  StringBuilder sbr = new StringBuilder();
  for (int i = 0; i < objArray.length; i++) {
   sbr.append(objArray[i]);
  }
  return sbr.toString();
 }
}

Monday, April 26, 2010

Threads: Producer-Consumer Problem

Producer-Consumer problem is a very common question related to threads. Following is a simple solution to the problem. QueueClass represents the queue which both the Producer and Consumer has to access. The critical methods in the QueueClass - add() and remove() are synchronized in order to maintain the status quo between the Producer and Consumer threads.


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

public class ProducerConsumerTest {

/**
* @param args
*/
public static void main(String[] args) {
QueueClass q = new QueueClass();
Producer p = new Producer(q, 10);
Consumer c = new Consumer(q, 10);

Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
c.setpThread(t1);
t1.start();
t2.start();
}

}

class Producer implements Runnable {
QueueClass q;
int size;

Producer(QueueClass q, int size) {
this.q = q;
this.size = size;
}

public void run() {
int index = -1;
while(true) {
q.add(new String("" + ++index));
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}

class Consumer implements Runnable {
QueueClass q;
int size;
Thread pThread;

public void setpThread(Thread pThread) {
this.pThread = pThread;
}

Consumer(QueueClass q, int size) {
this.q = q;
this.size = size;
}

public void run() {
while(true) {
q.remove();
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}

class QueueClass {
List queue = new ArrayList();
int size = 10;

public synchronized void add(String s) {
if(getSize() < size) queue.add(s);
System.out.println("Added: " + queue);
try {
if(getSize() >= size) {
notifyAll();
wait();
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}

public synchronized void remove() {
if(getSize() > 0) queue.remove(queue.size()-1);
System.out.println("Removed: " + queue);
try {
if(getSize() <= 0) {
notifyAll();
wait();
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}

public synchronized int getSize() {
return queue.size();
}
}

Thursday, March 04, 2010

Linked List

Linked list is a fundamental data structure, which uses reference stored in each node to iterate through subsequent nodes. A linked list has many types like singly linked list, doubly linked list and circular linked list. Following is a simple bare bone implementation of singly linked list:

The base interface:


public interface LinkedList {
public boolean add(T t);
public boolean remove(T t);
public void removeAll();
public int size();
public boolean isEmpty();
}

Class representing each node:

public class LinkNode {
private LinkNode nextNode = null;
private T node = null;

public LinkNode() {

}

public LinkNode(T node) {
this.node = node;
}

public T getNode() {
return node;
}

public void setNode(T node) {
this.node = node;
}

public LinkNode getNextNode() {
return nextNode;
}

public void setNextNode(LinkNode nextNode) {
this.nextNode = nextNode;
}

public String toString() {
return node.toString();
}

public int hashCode() {
return node.hashCode();
}

public boolean equals(LinkNode t) {
return node.equals(t.getNode());
}
}

Implementation for a singly linked list:

public class SingleLinkedList implements LinkedList {
LinkNode header = null;
LinkNode lastNode = null;

public SingleLinkedList() {

}

public boolean add(T t) {
LinkNode newNode = new LinkNode(t);
if(header == null) {
header = newNode;
}
else {
lastNode.setNextNode(newNode);
}
lastNode = newNode;
return true;
}

public boolean remove(T t) {
LinkNode tmp = header;
LinkNode prev = null;

while(tmp != null) {
if(tmp.getNode().equals(t)) {
if(prev == null) header = null;
else if(tmp.getNextNode() != null) prev.setNextNode(tmp.getNextNode());
return true;
}
prev = tmp;
tmp = tmp.getNextNode();
}
return false;
}

public void removeAll() {
header = null;
}

public boolean isEmpty() {
return header == null;
}

public int size() {
LinkNode tmp = header;
int size = 0;
while(tmp != null) {
size++;
tmp = tmp.getNextNode();
}

return size;
}

public String toString() {
StringBuffer str = new StringBuffer("[");
LinkNode tmp = header;
while(tmp != null) {
str.append(tmp.toString());
tmp = tmp.getNextNode();
if(tmp != null) str.append(", ");
}
str.append("]");
return str.toString();
}
}

Test class which uses the singly linked list implementation:

public class LinkedListTest {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList list = new SingleLinkedList();
System.out.println("Is list empty? " + list.isEmpty());

list.add("1");
list.add("2");
list.add("3");
list.add("2");
list.add("2");
list.add("3");
System.out.println(list.size());
System.out.println(list);
System.out.println("Is list empty? " + list.isEmpty());

list.remove("2");
System.out.println(list.size());
System.out.println(list);
System.out.println("Is list empty? " + list.isEmpty());

list.removeAll();
System.out.println("Is list empty? " + list.isEmpty());
}

}

Wednesday, March 11, 2009

How to be assertive

  • Assertions were introduced in J2SE 1.4
  • Rather than introducing it as a class library it was built into the language itself using the keyword assert
  • Assertions can be used to test the following three roles:
    • Precondition - a condition that the caller of a method agrees to satisfy
    • Postcondition - a condition that the method itself promises to achieve
    • Invariant - a condition that should always be true for a specified segment or at a specified point of a program
  • An assertion has a boolean expression that if evaluated as false indicates a bug in the code
    assert a !=b  : "Not Equal!!"
  • The message part after the : is optional, if given it is passed to the stack trace which is printed
  • When an assertion fails, it means that the application has entered an incorrect state
  • When the expression evaluates to false an AssertionError is thrown
  • A good practice is to terminate the application when the error is thrown, because the application may start functioning inappropriately after a failure
  • Assertions are disabled by default - to run an application with assertions enabled we have to give the option "-ea" or "-enableassertion"
    java -ea AssertionTest
  • The above command enables assertion for all classes except for the system classes
  • To turn on assertion in system classes we have to use "-esa" or "-enablesystemassertions"
  • To disable assertions we have to use "-da" or "-disableassertion", which is the default
  • Also, we can enable or disable assertions for specific classes or packages
    java -ea:com.test.ui.UIClass MainClass
    java -ea:com.javacourses.tests... -da:com.javacourses.ui.phone MyClass
  • The ellipsis ... is part of the syntax
  • Following is a sample class that uses assertion to check for invalid user input
    import java.io.*;

    public class AssertionTest {
    public static void main(String[] args) throws IOException {
    System.out.print("Enter your marital status: ");
    int c = System.in.read();
    switch((char)c) {
    case 's': case 'S':
    System.out.println("Single");
    break;
    case 'm': case 'M':
    System.out.println("Married");
    break;
    case 'd': case 'D':
    System.out.println("Divorced");
    break;
    default:
    assert !true : "Invalid Option";
    }
    }
    }

Friday, February 27, 2009

Thursday, January 22, 2009

Compiling Programmatically

Following example uses the JavaCompiler interface in Java 6 to programmatically compile a Java class:

public class CompilerExample {
public static void main(String[] args) {
String fileToCompile = "test.java"
javax.tools.JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, null, null, fileToCompile);
if (compilationResult == 0) {
System.out.println("Compilation is successful");
} else {
System.out.println("Compilation Failed");
}
}
}

Dive Into Java

Dive into Java
View more presentations or upload your own. (tags: java programming)

Tuesday, January 06, 2009

Reversing a String in Java

The following code shows different methods of reversing a String in Java. The simplest being using the reverse() method of StringBuffer, while the other methods use char array and recursion:

public class StringReverse {<br />	public static void main(String[] args) {<br />		String s = "zyxwvutsrqponmlkjihgfedcba";<br />		System.out.println(charReverse(s));<br />		System.out.println(recursiveReverse(s , new StringBuffer()));<br />		System.out.println(recursiveReverse2(s, new StringBuffer()));<br />		System.out.println(bufferReverse(s));<br />	}<br />	<br />	public static String charReverse(String s) {<br />		char[] cArr = s.toCharArray();<br />		StringBuffer reversed = new StringBuffer();<br />		for(int i=cArr.length-1; i>=0; i--) reversed.append(cArr[i]);<br />		return reversed.toString();<br />	}<br />	<br />	public static String recursiveReverse(String s, StringBuffer t) {<br />		if(s.length() > 0) {<br />			t.append(s.substring(s.length()-1));<br />			recursiveReverse(s.substring(0, s.length()-1), t);<br />		}<br />		return t.toString();<br />	}<br />	<br />	public static String recursiveReverse2(String s, StringBuffer sb) {<br />		if (s.length() == 1){<br />			sb.append(s);<br />		}<br />		else{<br />			recursiveReverse2(s.substring(1, s.length()), sb);  <br />			sb.append(s.substring(0,1));<br />		}<br />		return sb.toString();<br />	}<br />	<br />	public static String bufferReverse(String s) {<br />		StringBuffer sb = new StringBuffer(s);<br />		return sb.reverse().toString();<br />	}<br />}

Monday, January 05, 2009

HSQLDB

HSQLDB is a 100% Java database which is embeddable. It has a small footprint and can be used for self-contained applications. The source files, the JAR file and support documents can be downloaded from hsqldb.org. It also provides a JDBC driver. HSQLDB is perfect for quick implementation and testing.

Following is a sample program which uses the JDBC driver for creating a table, inserting some data in the table and listing the rows from the table:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.PreparedStatement;

public class HSQLTest {
Connection conn;
Statement stmt;
PreparedStatement add_stmt, get_stmt;

static {
try{
Class.forName("org.hsqldb.jdbcDriver").newInstance();
}
catch(ClassNotFoundException e) {
e.printStackTrace();
}
catch(InstantiationException e) {
e.printStackTrace();
}
catch(IllegalAccessException e) {
e.printStackTrace();
}
}

HSQLTest() {
try {
initializeDB();
createTable();
populateTable();
displayRows();
}
catch(SQLException e) {
e.printStackTrace();
}
}

void initializeDB() throws SQLException {
conn = DriverManager.getConnection("jdbc:hsqldb:db/test", "sa", "");
stmt = conn.createStatement();
}

public void createTable() throws SQLException {
String table_name = "sample_table";
DatabaseMetaData dbM = conn.getMetaData();
ResultSet rs = dbM.getTables(null, null, "%", null);
boolean found = false;
while(rs.next()) {
String s = rs.getString(3);
//System.out.println(s);
if(s.equalsIgnoreCase(table_name)) {
found = true;
break;
}
}

if(!found) {
String s = "CREATE TABLE " + table_name + "(id INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1000) PRIMARY KEY, " +
"category VARCHAR(40), name VARCHAR(40))";
stmt.execute("SET WRITE_DELAY FALSE;");
stmt.executeUpdate(s);
}
}

public void populateTable() throws SQLException {
stmt.executeUpdate("insert into SAMPLE_TABLE (category, name) values ('E0', 'Ben')");
}

public void displayRows() throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT * FROM SAMPLE_TABLE");
int numCols = rs.getMetaData().getColumnCount();
while(rs.next()) {
for(int i=1; i<=numCols; i++) {
System.out.println(rs.getString(i) + ": " + rs.getString(i));
}
}
}

public static void main(String[] args) {
HSQLTest hTest = new HSQLTest();
}
}

Friday, January 02, 2009

OOP Principles

In the process-oriented model, programs are written around "what is happening". This approach characterizes a program as a series of linear steps. This can be thought of as code acting on data.

But, object-oriented programming organizes a program around its data, i.e., objects, and a set of well-defined interfaces to that data. An object-oriented program can be characterized as data controlling access to code.

Following are the three mechanisms that are required to implement the object-oriented model:

Encapsulation
  • It is the mechanism that binds together code and the data it manipulates
  • It keeps both code and data safe from outside interference and misuse
  • The basis of encapsulation is the class
  • A class defines the structure and behavior (of code and data) that will be shared by a set of objects
  • Each object of a given class contains the structure and behavior defined by the class
  • A class is a logical construct, whereas an object has physical reality
  • The purpose of a class is to encapsulate complexity
  • There are mechanisms for hiding the complexity of the implementation inside the class
  • Each method or variable in a class may be marked private or public
  • The public interface of a class represents everything that external users of the class need to know, or may know
  • The private methods and data can only be accessed by code that is a member of the class
  • Any other code that is not a member of the class cannot access a private method or variable

Ineritance
  • It is the process by which one object acquires the properties of another object
  • It supports the concept of hierarchical classification
  • Without the use of hierarchies, each object would need to define all of its characteristics explicitly
  • However, by use of inheritance, an object need only define those qualities that make it unique within its class
  • It can inherit its general attributes from its parent
  • It is the inheritance mechanism that makes it possible for one object to be a specific instance of a more general case
  • If a given class  encapsulates some attributes, then any subclass will have the same attributes plus any that it adds as part of its specialization
  • This lets object-oriented programs grow in complexity linearly rather than geometrically

Polymorphism
  • Polymorphism is a feature that allows one interface to be used for a general class of actions
  • The specific action is determined by the exact nature of the situation
  • It can be expressed by the phrase - one interface, multiple methods
  • It is possible to design a generic interface to a group of related activities
  • This helps reduce complexity by allowing the same interface to be used to specify a general class of action
  • It is the compiler's job to select the specific action as it applies to each situation
  • There are three distinct forms of polymorphism
    • Method overloading
    • Method overriding through inheritance
    • Method overriding through the Java interface
  • Which overloaded method to call is decided at compile time through the reference type passed
  • The other two forms are part of runtime polymorphism
  • With runtime polymorphism, the decision as to which version of a method will be executed is based on the actual type of object whose reference is stored in the reference variable, and not on the type of the reference variable on which the method is invoked
  • The decision as to which version of the method to invoke cannot be made at compile time
  • That decision must be deferred and made at runtime
  • This is sometimes referred to as late binding or dynamic method binding
Another essential element of object-oriented programming is abstraction.
  • A powerful way to manage abstraction is through the use of hierarchical classifications
  • This allows us to layer the semantics of complex systems, breaking them into more manageable pieces
  • The complicated implementation details are hidden from the user
  • The user is given a simple interface to interact with, whereas inside the actual implementation of the interface there may be many complicated details


(Compiled from Java 2: The Complete Reference)

Monday, December 29, 2008

What is Java?

  • Java generally refers to a combination of three things
    • the Java programming language
    • the Java Virtual machine
    • the Java platform
  • Java the language is a high-level OOP language, influenced in various ways by C, C++ and Smalltalk
  • Java has been around officially since 1996
  • Java has evolved tremendously all through these years and has spawned a number of technologies like
    • Servlet technology
    • component technology like JavaBeans
    • JavaServerFaces
    • and a whole host of other technologies and tools
  • Its syntax was designed to be familiar to those familiar with C-descended "curly brace" languages, but with stronger OO principiles than those found in C++
  • One of Java's more controversial aspects is its incomplete object-orientation - Java primitives such as int, char, boolean etc. are not objects
  • The inclusion of primitives increases Java performance, but at arguably expense of code clarity
  • Java 5.0 introduces an "autoboxing" scheme to eliminate many uses of the wrapper classes, but in some ways it obsures what is really going on
  • Java is a fail early language - because of its syntatic restrictions, many programming failures are simply not possible in Java
  • With no direct access to pointers, pointer-arithmetic errors are non-existent
  • Using an object as a different type than what it was originally declared to be requires an explicit cast, which gives the compiler an opportunity to reject illogical programming, like calling a String method on an Image
  • Java is generally understood to be the most popular general-purpose computing language in use today

  • Java is generally thought of in terms of three platforms
    • Standard Edition(SE)
    • Enterprise Edition (EE)
    • Micro Edition (ME)
  • Each describes the combination of a language version, a set of standard libraries, and a virtual machine to execute the code
  • EE is a superset of SE - any EE application can assume the existence of all of the SE libraries
  • EE's use of the language is identical to SE's
  • Because of the limitations of small devices like phones and set-top boxes, Java ME differs significantly from its siblings
  • It is not a subset of SE
  • ME eliminates some language features, such as the float primitive and Float class, reflecting the computing limitations of the platforms it runs on

Java Runtime Environment
  • Java Runtime Environment is a subset of JDK
  • It is an implementation of the JVM which actually executes Java programs
  • JRE is a plug-in needed for running Java programs
  • JRE includes JVM, core libraries and other additional components to run applications and applets written in Java


Java Virtual Machine
  • One of the strong points in favor of Java is "Write Once, Run Anywhere"
  • Java is platform-independent
  • Before Java, programmers would have to write the program for the Windows OS and again for the Mac OS
  • Java eliminates this problem with the use of JVM
  • Java Virtual Machine as its name suggests is a "virtual" computer that resides in the real computer as a software process
  • The JVM essentially runs between the computer and the Java program
  • JVM gives Java the flexibility of platform independence
  • At some point, Java source needs to become platform-native executable code
  • This typically requires a two step process - the developer compiles the source into Java bytecode, and then a JVM converts this into native code for the host platform
  • Java code is written in a ".java" file
  • This code contains one or more Java language attributes like Class, Methods, Variables, Objects etc.
  • Javac is used to compile this code and to generate a ".class" file
  • Class file is also known as byte code
  • java byte code is an input to JVM
  • JVM reads this code and interprets it and executes the program
  • JVM helps the JRE to run Java applications
  • JVM operates on Java bytecode, which is normally generated from Java source code
  • A JVM can also be used to implement programming languages other than Java
  • For example, Ada source code can be compiled to Java bytecode, which may then be executed by a JVM
  • JVMs can also be released by other companies besides Sun - JVMs using the "Java" trademark may be developed by other companies as long as they adhere to the JVM specification published by Sun



Components of JVM
  • JVM is divided into several components like the stack, the garbage-collected heap, the registers and the method area
  • Stack in JVM stores various method arguments as well as the local variables of any method
  • Stack also keeps track of each and every method invocation - called the Stack Frame
  • There are three registers that helps in stack manipulation - vars, frame and optop
  • These registers point to different parts of current stack
  • There are three sections in Java stack frame
    • Local Variables - contains all the local variables being used by the current method invocation. It is pointed to by the vars register
    • Execution Environment - used to maintain the operations of the stack itself. It is pointed to by the frame register
    • Operand Stack - used as a work space by bytecode instructions. It is here that the parameters for bytecode instructions are placed, and the results of bytecode instructions are found. The top of the operand stack is pointed to by the optop register
  • Method Area - is the area where bytecode resides
  • The program counter points to some byte in the method area
  • It always keeps track of the current instruction which is being executed
  • After execution of an instruction, the JVM sets the PC to next instruction
  • Method area is shared among all the threads of a process
  • If more than one thread is accessing any specific method or instruction, synchronization is required
  • Synchronization in JVM is achieved through Monitors
  • Garbage-Collected Heap - is where the objects in Java programs are stored
  • Whenever an object is created using the new operator, the heap comes into picture and memory is allocated from there
  • unlike C++, Java doesn't have free operator to free any previously allocated memory
  • Java does this automatically using Garbage collection mechanism
  • "Mark and Sweep" algorithm is used as garbage collection logic
  • The local object reference resides on Stack, but the actual object resides in Heap
  • Arrays in Java are objects, hence they also reside in Garbage-Collected Heap


(Compiled from http://viralpatel.net/blogs/2008/12/java-virtual-machine-an-inside-story.html, Beyond Java and Widipedia)

Tuesday, December 23, 2008

Reflecting on Annotations

          The easiest way to check for an annotation is by using the isAnnotationPresent() method

­          This lets us specify the annotation to check for, and get a true/false result

public void testAnnotnPresent(PrintStream out) throws Exception {

      Class c = Super.class;

boolean inProgr = c.isAnnotationPresent(InProgress.class);

if(inProgr) out.println(“Super is in progress”);

else out.println(“Super is not in progress”);

 

}

­          This also lets us take advantage of the Inherited annotation

­          Although the Sub is not marked as in progress, it inherits from Super, which is in progress

­          Once the method in question is located, that method can be queried for a specific annotation using getAnnotation()

Class c = AnnotationTester.class;

MethodElement element = c.getMethod(“calculateInterest”,

                                    float.class, float.class);

GroupTODO groupTodo = element.getAnnotation(GroutpTODO.class);

String assignedTo = groupTodo.assignedTo();

out.println(“TODO Item on Annotation Tester is assigned to: ” +

assignedTo);

­          We must have to know exactly what we’re looking for – this is one of the few drawbacks of getAnnotation()

­           

­          We can use getAnnotations(), if we’re trying to locate all annotations for a program element, or if we need to iterate through all annotations looking for a specific one

­          Following is a simple utility method that prints out all annotations for a supplied element

public void printAnnotations(AnnotatedElement e) {

      System.out.println(“Annotations for “ + e.toString());

      Annotation[] annotations = e.getAnnotations();

for(Annotation a : annotations) {

      System.out.println(a.annotationType().getName());

}

}

­          The getAnnotations() method prints both declared as well as inherited annotations

­          To get declared annotations alone, we need to use getDeclaredAnnotations() method

­          java.lang.reflect.AnnotatedElement is an interface that the reflection constructs like Method, Class etc. implement

­          It allows access to the annotation methods

­          The core reflection constructs all implement this interface –

o        Class

o        Constructor

o        Field

o        Method

o        Package

o        AccessibleObject

­          This allows all the above elements to be introspected for annotations

­          All these element types provide the following methods as a result of implementing AnnotatedType

o        public Annotation getAnnotation(Class annotationType)

o        public Annotation[] getAnnotations()

o        public Annotation[] getDeclaredAnnotations()

o        public boolean isAnnotationPresent(Class annotationType)

­          Since any Java program element can be treated as an AnnotatedType, we can always get at an element’s annotations using these methods

­           

­          Reflection on annotations only works for annotation types that have Runtime retention

­          Even if the annotation is retained at compilation, if the VM doesn’t load this retention at class-load time, then reflection can’t pick up the annotation

­          Deprecation does not have runtime retention – it has source retention

­          So it is undetectable through Java reflection

­           

Meta Annotations

­          As we can annotate classes, we can also annotate custom annotations

­          Meta-annotations or annotations on annotations are helpful in figuring out someone else’s intent for a customized annotations

­          There are four standard meta-annotations, all defined in the java.lang.annotation package

o        Target

Specifies which program elements can have annotations of the defined type

o        Retention

Indicates whether an annotation is tossed out by the compiler, or retained in the compiled class file

In cases where the annotation is retained, it also specifies whether it is read by the JVM at class load

o        Documented

Indicates that the defined annotation should be considered as part of the public API of the annotated program element

o        Inherited

It is intended for use on annotation types that are targeted as classes, indicating that the annotated type is an inherited one

­           

­          Target

­          It is used to specify which program elements are allowed as targets for the defined annotation

­          This prevents misuse of an annotation, and is a sanity check for an annotation

­          Target should be used in the lines directly preceding the annotation definition

@Target({ElementType.TYPE, ElementType.METHOD

   ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})

public @interface TODO {

      ....

}

­          Target takes a single member whose type is an array of values, each of which should be an enumerated value from the java.lang.annotation.ElementType enum

­          This enum defines the various program elements allowed as targets of an annotation type

package java.lang.annotation;

 

public enum ElementType {

      TYPE,

      FIELD,

      METHOD,

      PARAMETER,

      CONSTRUCTIR,

      LOCAL_VARIABLE,

      ANNOTATION_TYPE,

      PACKAGE

}

­          To use Target we need to import both Target and ElementType

­          Following is the definition for the Target annotation

package java.lang.annotation;

 

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Target {

      ElementType[] value();

}

­          As we can see in the above definition, Target meta-annotation is used on itself

­          In case of annotation types that work for all program elements, we don’t have to use Target at all

­           

­          Retention

­          The Retention meta-annotation defines how the Java compiler treats annotations

­          Annotations can be tossed out of a compiled class file by the compiler, or kept in the class file

­          Additionally, the JVM can ignore annotations – when they are retained in the class file, or read those annotations at the time a class is first loaded

­          All of these options are specified by Retention

­           

­          Like Target, we specify the retention of an annotation type just before the annotation definition

­          Also like Target, the argument to Retention must be a value from an enum support class – java.lang.annotation.RetentionPolicy

package java.lang.annotation;

 

public enum RetentionPolicy {

      SOURCE,  //annotation is discarded by compiler

      CLASS,   //stored in the class file, but ignored by the VM

      RUNTIME  //stored in the class file and read by the VM

}

­          The default retention policy, for all annotations, is RetentionPolicy.CLASS

­          This retains annotations, but doesn’t require the VM to read them when classes are loaded

­          A good example of using Retention occurs in the SuppressWarnings annotation

­          As that annotation type is purely used for compilation – ensuring warning of the specified type are suppressed, it does not need to be retained in a class’s byte code

@Retention(RetentionPolicy.SOURCE)

public @interface SuppressWarnings {

      ....

}

­           

­          Documented

­          Annotations are not normally visible in the codes’ Javadoc

­          This is where the Documented meta-annotation comes into play

­          We can use it to ensure that our annotations show up in generated Javadoc

­          We need to add a @Documented meta-annotation to any annotation type that we want to appear in Javadoc

import java.lang.annotation.Documented;

import java.lang.annotation.Retention ;

import java.lang.annotation.RetentionPolicy ;

 

@Documented

@Retention(RetentionPolicy.RUNTIME)

public @interface InProgress { }

­          Anytime we use the Documented annotation, we should pair it with a retention policy of RetentionPolicy.RUNTIME

­           

­          Inherited

­          Annotations applied to super class are not automatically inherited by the sub-class

­          For example in the following code, InProgress annotation is not inherited by the sub-class Sub

@InProgress

public class Super {

      ....

}

 

public class Sub extends Super {

      ....

}

­          We need to used Inherited in the definition of the InProgress annotation type to fix this problem

@Documented

@Inherited

@Retention(RetentionPolicy.RUNTIME)

public @interface InProgress { }

­          The above definition will make any sub-class of a class annotated with the InProgress annotation inherit the annotation

­          Annotations marked as Inherited only apply to sub-classes, so implementing a method with annotations will not result in the annotations being inherited

­          If we override a method from a super class, we don’t inherit that specific method’s annotations

­          Only the annotations on the super class itself are inherited, and those and those by the sub-class as a whole

­