Tuesday, April 20, 2010

Generating documentation with APT and Maven

Purpose:-
Display the usage of APT to generate traceability matrix for requirement and test case.

This is not a fully implemented feature rather it displays the concepts and the setup.
This assumes basic understanding of APT and maven.

Steps:-
1. Setup project 'TestAnnotation' for annotation processor - change pom, write annotation and process classes
2. Update project 'Test' for annotation processing
3. execute apt

Step 1:

1.1 Create a new maven project 'TestAnnotation' and update the pom dependency to include tools.jar.

<dependency>
<groupid>com.sun</groupid>
<artifactid>tools</artifactid>
<version>1.4.2</version>
<scope>system</scope>
<systempath>${java.home}/../lib/tools.jar</systempath>
</dependency>


1.2 Write the annotation class. This class needs to be shared with the Test project. This can be done by copying the source unto the project or having a common dependency between the projects.

package com.sash;

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

@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE,
ElementType.METHOD,
ElementType.CONSTRUCTOR,
ElementType.PACKAGE,
ElementType.FIELD})
public @interface TestCaseDetails {
String code();
String description();
String useCase();
}
1.3 Create Annotation Processing Factory

The factory is responsible for creating processors for one or more annotation types. The factory is said to support these types.
package com.sash;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.apt.AnnotationProcessors;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;

public class TestCaseDetailsProcessorFactory implements
AnnotationProcessorFactory {

public AnnotationProcessor getProcessorFor(
Set <> declarations,
AnnotationProcessorEnvironment env) {
AnnotationProcessor result;
if (declarations.isEmpty()) {
result = AnnotationProcessors.NO_OP;
} else {
result = new TestCaseDetailsProcessor(env);
}
return result;

}

public Collection <> supportedAnnotationTypes() {
return Collections.singletonList(TestCaseDetails.class.getName());
}

public Collection <> supportedOptions() {
return Collections.emptyList();
}
}

1.4 Create the annotation processor

package com.sash;

import java.util.Collection;
import java.util.Map;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.util.SourcePosition;

public class TestCaseDetailsProcessor implements AnnotationProcessor {

private AnnotationProcessorEnvironment environment;

private AnnotationTypeDeclaration annotationTypeDeclaration;

public TestCaseDetailsProcessor(AnnotationProcessorEnvironment env) {
System.out.println("TestCaseDetailsProcessor.TestCaseDetailsProcessor()");
environment = env;
annotationTypeDeclaration = (AnnotationTypeDeclaration) environment
.getTypeDeclaration(TestCaseDetails.class.getName());
}

public void process() {
System.out.println("TestCaseDetailsProcessor.process()");
Collection declarations = environment
.getDeclarationsAnnotatedWith(annotationTypeDeclaration);
for (Declaration declaration : declarations) {
processNoteAnnotations(declaration);
}
}

private void processNoteAnnotations(Declaration declaration) {
System.out.println("TestCaseDetailsProcessor.processNoteAnnotations()");
Collection annotations = declaration
.getAnnotationMirrors();
for (AnnotationMirror mirror : annotations) {
if(mirror.getAnnotationType().getDeclaration().equals(
annotationTypeDeclaration)) {

SourcePosition position = mirror.getPosition();
Map values = mirror
.getElementValues();

System.out.println("Declaration: " + declaration.toString());
System.out.println("Position: " + position);
System.out.println("Values:");
for (Map.Entry entry : values
.entrySet()) {
AnnotationTypeElementDeclaration elemDecl = entry.getKey();
AnnotationValue value = entry.getValue();
System.out.println(" " + elemDecl + "=" + value);
}
}
}
}

}


2. Update the pom of project 'Test' for annotation processing to add apt maven plugin.


<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
</plugin>


Update the test case to use the annotations.

package com.test; import com.sash.TestCaseDetails;
public class Testing1 {
@Test
@TestCaseDetails(code="1", description="2", useCase="3")
public void testing() {
//actual code goes here
}
}


3. Execute the maven command 'mvn apt:test-process' to execute the command. The following output can be seen:-


Values:
code()="1"
description()="2"
useCase()="3"


The example only shows a print into the console. This should be written into a file with the expected format.

The apt command can also be executed without maven using the following command.


apt \TestAnnotation-1.jar -factory com.sash.TestCaseDetailsProcessorFactory \Testing1.java


Note: The code provided has been written by using articles and documentation available. This is only an aggregation of information available online.

Reference and further reading:
http://www.oracle.com/technology/pub/articles/marx-jse6.html
http://www.javalobby.org/java/forums/t17876.html
http://mojo.codehaus.org/apt-maven-plugin/examples/configuring-a-factory.html

Tuesday, December 8, 2009

GoF Design Patterns with examples using Java and UML

written by:
Benneth Christiansson (Ed.)
Mattias Forss,
Ivar Hagen,
Kent Hansson,
Johan Jonasson,
Mattias Jonasson,
Fredrik Lott,
Sara Olsson, and
Thomas Rosevall

Gof Design patterns

A very nice recap of the design patterns.

Saturday, July 25, 2009

Notational Conventions

Notational Conventions explained for many specifications:-
http://tools.ietf.org/html/rfc2119

Tuesday, July 7, 2009

Find Bugs

Find Bugs is an eclipse plugin which shows the common errors in Java. I use the eclipse plugin, and as a Best Practice for java developers this should be used while development. :)

e.g.
For a piece of code the following error was received

When piece of code in given below:-
1. Long id = request.getId();
2.
3. if(request == null || id == null) {
4. throw new RuntimeException("id cannot be null");
5. }
Find the error if you can... :)

The check for request == null is fruitless, since if request is null the line 1 will fail. Below is provided the corrected code and thus removes the bug.
1. if(request == null || request.getId() == null) {
2. throw new RuntimeException("id cannot be null");
3. }

Long id = request.getId();


A note of caution, the code inspection tools need to be used intelligently, it may sometimes flag code as bug that may have been done for some valid reason. Ignore them in this case.

Tuesday, June 30, 2009

Minimize memory footprint

An application to minimize memory footprint.

Minimem

The application can optimize the memory used. Some applications when run over a long time start hogging a lot of memory, this tools optimizes the memory usage and free it.

Mozilla is a good example of such a process (at least I was facing the issue) but is irreplaceable. :)