Download Java Programming II

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Java Programming II
Annotations and Reflection
Java Programming II
1
Contents










Annotations
Annotating Elements
Restricting Annotation Applicability
Retention Policies
The Class Class
Examples
Reflection
Annotation Queries
The Modifier Class
The Member classes
Java Programming II
2
Annotations
 The source code for our program is usually accompanied by copious
amounts of informal documentation that typically is contained within comments
in the source code
 Many organizations have a standard preamble: copyright information,
the programmers name, the date the class was created, etc.
 Other comments by external tools: version control in a source code
management system, or deployment descriptors on how a class should be
managed by an application server.
 Comments based annotation
 A better way to document the many annotations: to annotate the
program elements directly using annotation types
 Another motivation: many APIs require a fair amount of boilerplate
code. (For example, in order to write a JAX-RPC web service, you
must provide a paired interface and implementation. ) This boilerplate
could be generated automatically by a tool if the program were
“decorated” with annotations indicating which methods were remotely
accessible.
Java Programming II
3
Annotations
 Provide data about a program that is not part of the
program itself.
 Using annotation type to describe the form of the
annotations.
 Uses of Annotation
Information for the compiler — Annotations can be used
by the compiler to detect errors or suppress warnings.
Compiler-time and deployment-time processing —
Software tools can process annotation information to
generate code, XML files, and so forth.
Runtime processing — Some annotations are available
to be examined at runtime.
Java Programming II
4
Annotations
Documentation
Annotation Type
Using Annotation
Using Comments
/*-----------------------------Created: Jan 31 2005
Created By: James Gosling
Last Modified: Feb 9 2005
Last Modified By: Ken Arnold
Revision: 3
---------------------------------*/
public class Foo {
// …..
}
How to use Annotation
1. Define Annotation Type
2. Add Annotation using the
type
@interface ClassInfo {
String created();
String createdBy();
String lastModified();
String lastModifiedBy();
int revision();
}
@ClassInfo(
created = “Jan 31 2005”,
createdBy = “James Gosling”,
lastModified =“Feb 9 2005”,
lastModifiedBy =“Ken Arnold”,
revision =3
) public class Foo {
// class definition…
Annotation for the
}
class Foo
Java Programming II
5
Annotation Types
 Constraint rules of the methods declared in an annotation type (elements
of annotation type)
 The type of the element can only be a primitive type, String , enum, another
annotation type, Class, or an array of the preceding types.
 Cannot declare any parameters.
 Cannot have a throws clause.
 Cannot define a type parameter, i.e cannot be a generic method.
@interface Revision {
int major() default 1;
int minor() default 0;
}
@interface ClassInfo {
String created();
String createdBy();
String lastModified();
String lastModifiedBy();
Revision revision();
}
Initialization expression
@ClassInfo (
created = “Jan 31 2005”,
createdBy = “James Gosling”,
lastModified = “Feb 9 2005”,
lastModifiedBy = “Ken Arnold”,
revision = @Revision(major=3)
)
public class Foo {
// …
- Marker annotation: annotation type
}
which has zero elements
(ex) public @interface Preliminary { }
Java Programming II
6
Annotation Used by Complier
 @Deprecated—the @Deprecated
annotation indicates that the marked
element is deprecated and should no
longer be used. When an element is
deprecated, it should also be
documented using the Javadoc
@deprecated tag.
// Javadoc comment follows
/**
* @deprecated
* explanation of why it was deprecated
*/
@Deprecated
static void deprecatedMethod() { }
}
 @Override—the @Override annotation informs the compiler that the
element is meant to override an element declared in a superclass
(overriding methods will be discussed in the the lesson titled "Interfaces
and Inheritance").
 @SuppressWarnings—the
@SuppressWarnings annotation tells the
compiler to suppress specific warnings that it
would otherwise generate . In the example of
the right site, a deprecated method is used
and the compiler would normally generate a
warning. In this case, however, the annotation
causes the warning to be suppressed.
@SuppressWarnings(deprecation)
void useDeprecatedMethod() {
objectOne.deprecatedMethod();
// deprecation warning suppressed
}
}
Java Programming II
7
Annotating Elements and Restricting Annotation
Applicability

Marker annotation or all its
elements have default
values
@Deprecated
public void badMethod() {/* … */}
 (an empty list of initializers)
@Deprecated()
public void badMethod() {/* … */}

Array initializer expression
@interface BugsFixed {
String[] bugIds();
}

@BugsFixed(bugIDs = {“1234”,
“4567”})
or
@BugsFixed(bugIDs = “4567”)

When has only a single
element (naming of the
element is value), it
allows for additional
shorthand:
@inteface BugsFixed {
String[] value();
}

@BugsFixed({“1234”,”4567”})
@BugsFixed(“4567”)
Java Programming II
8
Retention Policies

Annotation can serve many
different purposes and may be
intended for different readers
(programmers, or a development tool,
compiler, some tool that may need to
extract the annotations from a binary
representation of a class, and to be
inspected at runtime)


The Target annotation type
Enum constant of ElementType
: Represents the different kinds of
program elements to which
annotations can be applied.




ANNOTATION_TYPE : Annotation
type declaration
CONSTRUCTOR : Constructor
declaration
FIELD : Field declaration (includes
enum constants)
LOCAL_VARIABLE : Local variable
declaration




METHOD : Method declaration
PACKAGE : Package declaration
PARAMETER : Parameter declaration
TYPE : Class, interface (including
annotation type), or enum
declaration
 Example
@Target (ElementType.TYPE)
@interface ClassInfo {
String created();
String createdBy();
This will be
String lastModified();
applied to
type
String lastModifiedBy();
declaration
Revision revision();
}
Java Programming II
9
Retention Policies

Three Retention Policies
Can be applied when the annotation can be accessed.
(Used by @Retention type, Defined by the RetentionPolicy
enum)



SOURCE: Annotations exist only in the source file
CLASS: preserved in the binary representation of the class,
but not available at run time
RUNTIME: must be available at runtime via the reflection
mechanism
 Example
@Retention(RetentionPolicy.RUNTIME)
Java Programming II
10
The “Class” class

The Class class defines
these methods:




getName – returns the
(class) name
getFields – returns all the
public fields
getMethods – returns all the
public methods
getPackage – returns the
class’ package




Java Programming II
getSuperclass – returns the
class’ superclass
getConstructors – returns all
the public constructors
static Class<?>
forName(String className)
- returns Class object
Annotation[]
getAnnotations() - returns all
annotations present on this
element.
11
Working with Annotations (I)

A simple annotation-based test
framework
“RunTests.java”
import java.lang.reflect.*;
“Foo.java”
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Test { }
public class RunTests {
public static void main(String[] args) throws
Exception {
int passed = 0, failed = 0;
for (Method m :
Class.forName(args[0]).getMethods()) {
Add “Test”
if (m.isAnnotationPresent(Test.class)) {
Annotation
public class Foo {
try {
@Test public static void m1() { }
m.invoke(null);
public static void m2() { }
passed++;
@Test public static void m3() {
} catch (Throwable ex) {
throw new RuntimeException("Boom");
System.out.printf("Test %s failed: %s %n",
}
m, ex.getCause());
public static void m4() { }
failed++;
@Test public static void m5() { }
}
public static void m6() { }
}
@Test public static void m7() {
}
throw new RuntimeException("Crash");
System.out.printf("Passed: %d, Failed %d%n",
}
passed, failed);
public static void m8() { }
}
}
}
Run:
% java RunTests Foo
Java Programming II
12
Working with Annotations (II)

BugsFixedExample: Using Class
and getAnnotation method of the
“ClassInfo” class
“MyFoo.java”
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface BugsFixed {
String[] value();
}
@BugsFixed( {"1234", "5678"} )
public class MyFoo {
}
“BugsFixedExample.java”
public class BugsFixedExample {
public static void main(String[] args) {
Class<MyFoo> cls = MyFoo.class;
BugsFixed bugsFixed =
(BugsFixed)
cls.getAnnotation(BugsFixed.class);
System.out.println(bugsFixed);
String[] bugIds = bugsFixed.value();
for (String id : bugIds)
System.out.println(id);
}
}
Run:
% java BugsFixedExample
Java Programming II
13
Documentation Comments

A Simple Example
/**
* An <code>Attr</code> object defines an attribute as a
* name/value pair, where the name is a <code>String</code>
* and the value an arbitray <code>Object</code>.
*
* @version 1.1
* @author Plago
* @since 1.0
*/
public class Attr {
/** The attribute name. */
private final String name;
/** The attribute value. */
private Object value = null;
/** Returns this attribute's name. */
public String getName() {
return name;
}
/** Returns this attribute's value. */
public Object getValue() {
return value;
}
/**
* Sets the value of this attribute. Changes the
* value returned by calls to {@link #getValue}.
* @param newValue The new value for the attribute.
* @return The Original value.
* @see #getValue()
*/
public Object setValue(Object newValue) {
Object oldVal = value;
value = newValue;
return oldVal;
}
/**
* Crates a new attribute with the given name and an
* initial value of <code>null</code>.
* @see Attr#Attr(String,Object)
*/
public Attr(String name) {
this.name = name;
}
/**
* Creates a new attribute with the given name and
* inital value.
* @see Attr#Attr(String)
*/
public Attr(String name, Object value) {
this.name = name;
this.value = value;
}
/**
* Returns a string of the form <code>name=value</code>.
*/
public String toString() {
return name + "='" + value + "'";
}
}
Run:
% javadoc Attr.java
Java Programming II
14
Reflection

The reflection is to
examine a type in detail.



The reflection package :
java.lang.reflect
Reflection starts with a
Class object
A simple example of a
“type browser”.
Argument:
import java.lang.reflect.*;
import static java.lang.System.out;
import static java.lang.System.err;
public class SimpleClassDesc {
public static void main(String[] args) {
Class type = null;
try {
type = Class.forName(args[0]);
} catch(ClassNotFoundException e) {
err.println(e);
return;
}
Attr.class
out.print("class " + type.getSimpleName());
Class superclass = type.getSuperclass();
if (superclass != null)
out.println(" extends " +
superclass.getCanonicalName());
else out.println();
Run:
% java SimpleClassDesc Attr
Result:
class Attr extends java.lang.Object
public java.lang.String Attr.getName()
public java.lang.String Attr.toString()
public java.lang.Object Attr.getValue()
public java.lang.Object Attr.setValue(java.lang.Object)
Method[] methods = type.getDeclaredMethods();
for (Method m : methods)
if (Modifier.isPublic(m.getModifiers()))
out.println(" " + m);
}
}
The source code is at the /home/course/java2/code/AnnotationReflection/
Java Programming II
15
The Introspection Hierarchy
Type
ParameterizedType
GenericArrayType
TypeVariable<D>
AnnotatedElement
WildcardType
AccessibleObject
GenericDeclaration
Member
Class
Constructor
Method
Java Programming II
Field
Package
16
Type Tokens
 Type Token



Each Class object for a
reference type is of a
parameterized type
corresponding to the class it
represents. (Ex: the type of
String.class is Class<String>)
A parameterized Class type is
known as the type token for a
given class
The easiest way to obtain a
type token is to use a class
literal.
class literal
import java.util.*;
public class TypeTokenTest {
public static void main(String[] args) {
Class<String> c1 = String.class;
System.out.println("Result1 = " + c1.getClass());
String str = "Hello";
// Class<String> c2 = str.getClass(); // error!
Class<? extends String> c2 = str.getClass();
System.out.println("Result2 = " + c2);
try {
Class<?> c3 =
Class.forName("java.lang.String"); //valid
Class<? Extends String> c3 =
Class.forName("java.lang.String"); //invalid
System.out.println("Result3 = " + c3);
} catch(ClassNotFoundException e) {
System.err.println(e); return;
}
Exact type token
How about this?
}
}
Class<? extends String> c3 =
Class.forName("java.lang.String").asSubclass(String.class);
Java Programming II
17
Class Inspection
import java.lang.reflect.*;
public class TypeDesc {
public static void main(String[] args) {
TypeDesc desc = new TypeDesc();
for (String name : args) {
try {
Class<?> startClass = Class.forName(name);
desc.printType(startClass, 0, basic);
} catch (ClassNotFoundException e) {
System.err.println(e); // report the error
}
}
}
// by default print on standard output
private java.io.PrintStream out = System.out;
// used in printType(U) for labeling type names
private static String[]
basic = {"class", "interface", "enum", "annotation"},
supercl = {"extends", "implements"},
iFace = {null, "extends"};
private void printType(
Type type, int depth, String[] labels) {
if (type == null) // stop recursion -- no supertype
return;
// turn the Type into a Class object
Class<?> cls = null;
if (type instanceof Class<?>) {
cls = (Class<?>) type; }
else if (type instanceof ParameterizedType) {
cls = (Class<?>)
((ParameterizedType)type).getRawType(); }
else
throw new Error("Unexpected non-class type");
Get type
token
// print this type
for (int i = 0; i < depth; i++)
out.print(" ");
int kind = cls.isAnnotation() ? 3 :
cls.isEnum() ? 2 :
cls.isInterface() ? 1 : 0 ;
out.print(labels[kind] + " ");
out.print(cls.getCanonicalName());
// print generic type parameters if present
TypeVariable<?>[] params = cls.getTypeParameters();
if (params.length > 0) {
out.print('<');
for(TypeVariable<?> param : params) {
out.print(param.getName());
out.print(", ");
}
out.println("\b\b>");
}
else out.println();
// print out all interfaces this class implements
Type[] interfaces = cls.getGenericInterfaces();
for (Type iface : interfaces) {
printType(iface, depth + 1,
cls.isInterface() ? iFace : supercl);
}
// recurse on the superclass
printType(cls.getGenericSuperclass(),
depth + 1, supercl);
} // end of main
} // end of clss
The source is at the “/home/course/java2/code/ByTopics/AnnotationReflection/Reflection”
Java Programming II
18
Class Inspection
Run:

% java TypeDesc
java.util.HashMap

Result:
class java.util.HashMap<K, V>
implements java.util.Map<K, V>
implements java.lang.Cloneable
implements java.io.Serializable
extends java.util.AbstractMap<K,
V>
implements java.util.Map<K, V>
extends java.lang.Object


Examining the kind of
Class object
Ask whether have a toplevel type or a nested type,
and if nested, some
information about which
kind of nested type
Find out where a type fits
in the type hierachy
Apply to a subset of those
different kinds.
Java Programming II
19