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.
|
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);
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
}
. . . .
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.
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
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.
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
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.
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.
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