Advertisment

Catching Java Bugs with Tiger

author-image
PCQ Bureau
New Update

Java programming language has matured tremendously over the

years. It has been able to safeguard against common programming pitfalls such as

array bounds checking, exception handling, memory leaks, dangling references

etc. But, there are still some lacunas in the language, such as typecasting and



excessive use of deployment descriptors (DD), which are processed independently

from the source code. In this article, we'll look at two popular features

namely Generics and Annotations introduced in Java SE 5 (aka Tiger) to catch

bugs early and drive agile development. Catching bugs early helps in preventing

their propagation in the later stages of the development cycle.

Advertisment
Direct

Hit!
Applies to:

Java SE/EE developers

USP:

Ensure compile-time type safety with Tiger
Links:

http://java.sun.com/j2se/1.5.0 
Google keywords:

Generics, annotations

A date with common programming bugs Java collection offers

excellent data structure support, and  is used to hold heterogeneous

objects, where the elements may have any reference type. Some common programming

bugs lead to ugly ClassCastException. For instance, when you add an integer to a

vector, while extracting the collection, an object is



returned that must be explicitly cast to an integer in order to



ensure type safety.

Vector v = new Vector();



v.add(new Integer(1));


Integer num = (Integer) v.get(0);




Advertisment

This kind of programming style makes it difficult to read

and maintain the code. Down casting is often the cause of errors as shown below.

class Facade{



//application logic


}


class MVC_View{


//client view


}







. . . .



Advertisment

Vector v = new Vector();



// Add an object of type Facade


v.add(new Facade());




// extract the object back



MVC_View b = (MVC_View) v.get(0);


Although the above code snippet compiles fine but at

runtime, it throws ClassCastException.

Advertisment

Generics to the rescue



Generics provide compile-time type safety and eliminate the need for casts.

With Generics, errors are flagged where they occur, and not later at run time.

Parametric types (eg vector, hashtable) provide an elegant way to implement

generic-utility classes that alleviates the need to cast and allow errors to be

caught at compile time. As shown in the following code snippet, with Generics,

you no longer have to keep track of what types of objects your collection

contains.

Vector v = new

Vector();







v.add(1);


int num = v.get(0);


The code snippet above uses another feature called

autoboxing introduced in Tiger. If you were to assign an extracted



element to a different type, the error would be caught at compile-time instead

of run-time.

Advertisment

This early static checking increases the type safety.

Here's another example that demonstrates how Generics can catch some potential

bugs at the compile time. This code segment will result in compilation error.

Vector v = new

Vector();



// Add an object of type Facade


v.add(new Facade());


// extract the object back


MVC_View b = (MVC_View) v.get(0);




Metadata meets Java



Metadata is data about data. It is useful in compile-time checking and code

analysis and does not directly affect the



semantics of a program. Development and deployment tools can inspect these

annotations and process them in some fashion and may produce additional source

files, such as XML documents, or other artifacts. Java SE5 lets the developer

use metadata in source code to include special directives. Lets now see how we

can put it to use.

Advertisment

Decorate your code with annotations



The metadata feature introduced in Java SE 5 is Annotations. With

Annotations, developers can dress their code to provide



documentation, code generation, and deliver container services to POJOs. Here

we'll explore some built-in annotations in Tiger. The first built-in

annotation type is Override. It indicates that the annotated method is

overriding a method in a superclass, and, it can only be applied to methods as

shown below.



public class TestOverride {

  @Override



  public String toString() {


    return super.toString() + " Testing Override
annotation";



  }


  @Override


  public int hashCode() {


    return toString().hashCode();







  }


}







If a method marked with Override annotation does not

override its super-class's method, the compiler will generate an error.

Advertisment

Next, we'll look at another marker annotation called

Deprecated. Like other deprecated methods, a method marked with this annotation

should not be used and the compiler flags a warning if such method is called.

//

TestDeprecatedAnnotation.java



public class

TestDeprecatedAnnotation {



   public static

void main(String arg<>)  {





new TestDeprecatedAnnotation();



   }



   public

TestDeprecatedAnnotation() {



   TestDeprecated

t=new TestDeprecated();





t.doDirectPurchase();


}

Delivering container services to POJOs



The real power of annotations can only be realized if one looks into the EJB 3.0
specification. With EJB 3.0, business components are developed as POJOs (Plain

Old Java Objects), and developers can use metadata annotations to specify to the

container how these beans are to be managed. With the new EJB 3.0 specification,

there's no need of boilerplate code, and DD (Deployment


Descriptors) are optional. Thanks to annotations, EJB 3.0

decreases the number of  programming artifacts that the developers need to

provide,



and eliminates/minimizes callback methods required to be implemented.

Annotations can be used to define the bean's business interface, O/R mapping

information, and inject dependencies at runtime. The following code snippet

shows how annotations help in simplifying the EJB development



experience.

@Remote



@Stateless public class HellodBean {


public String sayHello(String s){


System.out.println("Hello: "+s; }


}






It can't get simpler than this. You no longer need to

implement the javax.ejb.SessionBean interface or define separate remote (or

local) and home interface.

Even if you explicitly define one, it can be a POJI (Plain

Old Java Interface) called business interface, and, need not extend to EJBObject

or EJBLocalObject. If you do not implement an interface, a bean interface will

be generated for you. The type of generated interface, either local or remote,

is dependent on the annotation you used in the bean class. All the public

methods of the bean class will be included as part of the automatically

generated business interface.

Further, now there is no ejb-jar.xml DD required. XML files

can express complex relationships, but they are also quite verbose and less

robust. Annotations, on the other hand, are simple and concise. XML based DD

files are optional in EJB 3.0 and can be used to override annotation behavior.

Conclusion



Tiger is believed to be the biggest leap forward in Java



programming with significant extensions to the language syntax. Advanced

features such as auto-boxing and un-boxing of primitives, static imports,

variable method arguments, and enumerations are now supported.

Reflection in Java SE 5 has also been extended to support



reflecting on generic types.

In addition to using generic types, you can implement your

own types. Annotations are driving the next wave in agile



development. You can define your own custom application



specific annotations. Annotations alleviate boilerplate code and XML documents,

resulting in much cleaner and readable code. 

Kunal Jaggi

Advertisment