public static interface PublicMethod
extends Annotation
{
}
public static interface PrivateMethod
extends Annotation
{
}
上面是Palm裡面用到的Annotation,特轉載下面一篇文章(http://www.ericdlarson.com/misc/chrome_command_line_flags.html)。
Declarative Programming in Java
by Narayanan Jayaratchagan
04/21/2004
What makes EJB components special is the declarative programming model through which we can specify the services such as security, persistence, transaction etc., that the container should provide. An EJB only implements the business logic; the services are associated through a deployment descriptor, which essentially acts as metadata for the EJB. At runtime, the container uses the metadata specified in the deployment descriptor to provide the services. The deployment descriptor is an XML file, not part of the Java classes that make up the EJBs. Is there a standard way to annotate the Java classes that make up the EJBs so that a developer can look at the class definition, together with annotations, and know everything about that class? It would be even better if the remote, home interfaces and the deployment descriptor could be automatically generated by a tool using the annotations. Better yet, can we provide the same kind of declarative services for a simple Java object? If so, how? This article examines how JSR-175: A Metadata Facility for the Java Programming Language will help us in finding answers to these questions and more.
Approaches to Programming
There are two approaches to programming called imperative programming and declarative programming. Imperative programming gives a list of instructions to execute in a particular order -- Java program that counts the number of words in a text file is an example of the imperative approach. Declarative programming describes a set of conditions, and lets the system figure out how to fulfill them. The SQL statement SELECT COUNT(*) FROM XYZ
is an example for the declarative approach. In other words, "specifying how" describes imperative programming and "specifying what is to be done, not how" describes declarative programming.
Annotations
The Tiger release of Java (JDK 1.5) adds a new language construct called annotation (proposed by JSR-175). Annotation is a generic mechanism for associating metadata (declarative information) with program elements such as classes, methods, fields, parameters, local variables, and packages. The compiler can store the metadata in the class files. Later, the VM or other programs can look for the metadata to determine how to interact with the program elements or change their behavior.
Declaring an Annotation
Declaring an annotation is very simple -- it takes the form of an interface declaration with an @
preceding it and optionally marked with meta-annotations, as shown below:
package njunit.annotation;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface UnitTest {String value();}
The Retention
meta-annotation declares that the @UnitTest
annotation should be stored in the class file and retained by the VM so it may be read reflectively. The Target
meta-annotation declares that the @UnitTest
annotation can be used to annotate methods in a Java class. @interface
declares the @UnitTest
annotation with one member called value
, which returns a String
.
Using an Annotation
Here is an example that shows how to use the @UnitTest
annotation declared in the previous section:
import njunit.annotation.*;public class Example { @UnitTest(value="Test 1. This test will pass.") public void pass() { assert 10 > 5; } @UnitTest("Test 2. This test will fail.") public void fail() { assert 10
An annotation is applied to the code element by placing an annotation statement (@AnnotationType(...)
) before the program element. Annotation values take the form "name=value"
; for example, @UnitTest(value="some text")
. Single-member annotations with a member named value
are treated specially and can use the shorthand @UnitTest("some text")
. In the example, the @UnitTest
annotation is associated with the pass
and fail
methods.
Accessing Annotations at Runtime
Once annotations have been associated with program elements, we can use reflection to query their existence and get the values. The main reflection methods to query annotations are in a new interface: java.lang.reflect.AnnotatedElement
.
Methods available in the AnnotatedElement
interface are:
boolean isAnnotationPresent(Class extends Annotation> annotationType)
Returns true
if an annotation for the specified type is present on this element, elsefalse
. This method is designed primarily for convenient access to marker annotations.
T getAnnotation(Class annotationType)
Returns this element's annotation for the specified type if such an annotation is present, else null.
Annotation[] getAnnotations()
Returns all annotations present on this element. (Returns an array of length zero if this element has no annotations.)
Annotation[] getDeclaredAnnotations()
Returns all annotations that are directly present on this element. Unlike the other methods in this interface, this method ignores inherited annotations. (Returns an array of length zero if no annotations are directly present on this element.)
You may notice that the isAnnotationPresent
and getAnnotation
methods are defined using generics, another new feature available in JDK 1.5.
Here is the list of classes that implement the AnnotatedElement
interface:
java.lang.reflect.AccessibleObject
java.lang.Class
java.lang.reflect.Constructor
java.lang.reflect.Field
java.lang.reflect.Method
java.lang.Package
Next, I'll show you an example that illustrates how to access annotations at runtime.
package njunit;import java.lang.reflect.*;import njunit.annotation.*;public class TestRunner { static void executeUnitTests(String className) { try { Object testObject = Class.forName(className).newInstance(); Method [] methods = testObject.getClass().getDeclaredMethods(); for(Method amethod : methods) { UnitTest utAnnotation = amethod.getAnnotation(UnitTest.class); if(utAnnotation!=null) { System.out.print(utAnnotation.value() + " : " ); String result = invoke(amethod, testObject); System.out.println(result); } } }catch(Exception x) { x.printStackTrace(); } } static String invoke(Method m, Object o) { String result = "passed"; try{ m.invoke(o,null); } catch(Exception x) { result = "failed"; } return result; } public static void main(String [] args) { executeUnitTests(args[0]); }}
The TestRunner
uses the @UnitTest
annotation to determine whether a method is a unit test or not, invoke the method if it is marked with the @UnitTest
annotation, and report the success or failure.
Here is how the TestRunner
executes the unit test. Given a Java class, the TestRunner
first obtains the list of all declared methods using reflection. Then it queries each method using the enhanced for
construct and the getAnnotation
method available in JDK 1.5 to find out whether it is marked as a @UnitTest
. If it is marked, then it invokes the method and reports the success or failure. A test is considered failed if there is any exception when executing the test, and is considered passed otherwise.
In our Example
class, the pass
method will succeed when invoked, but the fail
method will throw an AssertionError
, which is propagated to the TestRunner.invoke
method as InvocationTargetException
.
When run with the command java -ea njunit.TestRunner Example
, the output looks like the following:
Test 1. This test will pass. : passedTest 2. This test will fail. : failed
Pages: 1, 2, 3
Next Page