Slide navigation: Forward with space bar, → arrow key, or PgDn. Backwards with ← or PgUp.
Copyright © Cay S. Horstmann 2016
@Test public void testEmptyInput() { ... }
instanceof
checks, and method references.@Test(timeout=10000)
String
, Class
, or an enumerated type.@BugReport(showStopper=true, assignedTo="Harry", testCase=CacheTest.class, status=BugReport.Status.CONFIRMED)
timeout
in @Test
is 0L
.value
, you can omit the key:
@SuppressWarnings("unchecked") // Same as @SuppressWarnings(value="unchecked")
@BugReport(reportedBy={"Harry", "Fred"})
@BugReport(reportedBy="Harry") // Same as {"Harry"}
@BugReport(ref=@Reference(id=11235811), ...)
@Test @BugReport(showStopper=true, reportedBy="Joe") public void checkRandomInsertions()
@BugReport(showStopper=true, reportedBy="Joe") @BugReport(reportedBy={"Harry", "Carl"}) public void checkRandomInsertions()
enum
) and interfaces (including annotation interfaces).
@Entity public class User { ... }
@SuppressWarnings("unchecked") List<User> users = ...; public User getUser(@Param("id") String userId)
public class Cache<@Immutable V> { ... }
@GPL(version="3") package com.horstmann.corejava; // Inpackage-info.java
import org.gnu.GPL; // Imports theGPL
annotation
public User getUser(@NonNull String userId)
// userId
is assumed to be non-null
List<String> userIds
and want to record the assumption that all elements are non-null.userIds
variable.List<@NonNull String> userIds
@NonNull String[][] words, String @NonNull [][] words, String[] @NonNull [] words
if (text instanceof @Localized String) public String read() throws @Localized IOException List<@Localized ? extends Message> @Localized Message::getText
public boolean equals(@ReadOnly Object other)
this
isn't mutated?public boolean equals(@ReadOnly Point this, @ReadOnly Object other)
public boolean equals(Point this, Object other)
.this
parameter of an inner class constructor:
public class Sequence { class Iterator implements java.util.Iterator<Integer> { public Iterator(@ReadOnly Sequence Sequence.this) { ... } } ... }
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Test { long timeout(); ... }
@interface
declaration creates an actual Java interface.@Target
and @Retention
are meta-annotations: annotations of annotations.@Target
specifies what this annotation can be applied to.@Retention
specifies where the annotation can be accessed.
SOURCE
, CLASS
, RUNTIME
default
clause after the interface method:
public @interface Test { long timeout() default 0L; ... }
public @interface BugReport { String[] reportedBy() default {}; // Defaults to empty array Reference ref() default @Reference(id=0); // Default for an annotation ... }
@Deprecated
annotation to mark deprecated features. If anyone uses them, the compiler will emit a warning.@Override
annotation makes the compiler check that you really override a method:
public class Point { @Override public boolean equals(Point other) { ... } ... }
@SuppressWarnings
annotation suppresses compiler warnings. Typical use:
@SuppressWarnings("unchecked") T[] result = (T[]) Array.newInstance(cl, n);
@FunctionalInterface
annotation checks that an interface has a single abstract method:
@FunctionalInterface public interface IntFunction<R> { R apply(int value); }
@Target
and @Retention
annotations:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Test { ... }
@Documented
annotation indicates that the annotation should be included in documentation such as Javadoc.
@FunctionalInterface
is documented, @SuppressWarnings
is not.@Inherited
applies to annotations for classes, and indicates that subclasses inherit the annotation:
@Inherited @interface Persistent { } @Persistent class Employee { . . . } class Manager extends Employee { . . . } // Also @Persistent
@Repeatable
indicates that an annotation can be applied multiple times.@Repeatable
, you can apply the same annotation multiple times :
@TestCase(params="4", expected="24") @TestCase(params="0", expected="1") public static long factorial(int n) { ... }
value
is an array of annotations:
@TestCases({ @TestCase(params="4", expected="24"), @TestCase(params="0", expected="1") }) public static long factorial(int n) { ... }
@Repeatable(TestCases.class) @interface TestCase { String params(); String expected(); } @interface TestCases { TestCase[] value(); }
@Deprecated
has since
and forRemoval
attributes.java.util
classes Observable
, Observer
(but not Vector
, Hashtable
).Object.finalize
and Runtime.runFinalizersOnExit
methods.toString
format.toString
methods, so we'll provide a static method ToStrings.toString(Object obj)
obj
and prints a string such as:
Point[x=5,y=10]
@ToString
annotation to customize the format:
@ToString(includeName=false) public class Point { @ToString(includeName=false) private int x; @ToString(includeName=false) private int y; ... }
Point
objects are printed as [5, 10]
.@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ToString { boolean includeName() default true; }
ToStrings.toString
, get the annotation of the class and its fields:
Class<?> cl = obj.getClass(); ToString classAnnotation = cl.getAnnotation(ToString.class); for (Field f : cl.getDeclaredFields()) { ToString fieldAnnotation = f.getAnnotation(ToString.class); if (fieldAnnotation.includeName()) ... ... }
getAnnotationsByType(cl)
to get an array of the annotations.ToStrings
example, we can generate source code for that utility class:
public class ToStrings { public static String toString(Point obj) { Generated code } public static String toString(Rectangle obj) { Generated code } ... public static String toString(Object obj) { return Objects.toString(obj); } }
ToStrings
Class@ToString public class Rectangle { ... @ToString(includeName=false) public Point getTopLeft() { return topLeft; } @ToString public int getWidth() { return width; } @ToString public int getHeight() { return height; } }
public static String toString(Rectangle obj) { StringBuilder result = new StringBuilder(); result.append(“Rectangle[”); result.append(toString(obj.getTopLeft())); result.append(“,width=”); result.append(toString(obj.getWidth())); result.append(“,height=”); result.append(toString(obj.getHeight())); result.append(“]”); return result.toString(); }
javac -processor ToStringAnnotationProcessor *.java
-XprintRounds
flag.javax.lang.model
API:
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment currentRound) {
...
JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(
"com.horstmann.annotations.ToStrings");
PrintWriter out = new PrintWriter(sourceFile.openWriter());
Print code for package and class
for (Element e : currentRound.getElementsAnnotatedWith(ToString.class)) {
if (e instanceof TypeElement) {
TypeElement te = (TypeElement) e;
Print code for toString
method
}
}
}
javac com/horstmann/annotations/ToStringAnnotationProcessor.java javac -processor com.horstmann.annotations.ToStringAnnotationProcessor sourcelevel/*.java java sourcelevel.SourceLevelAnnotationDemo
public static void premain(String arg, Instrumentation instr)
Premain-Class: MyAgent
jar cvfm MyAgent.jar manifest.mf *.class
java -javaagent:MyAgent.jar=agentArgument MyProg
@LogEntry(logger=loggerName)
Logger.getLogger(loggerName).entering(className, methodName);
May 17, 2016 10:57:59 AM Item hashCode FINER: ENTRY
LogEntry
annotation.ldc loggerName invokestatic java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger; ldc className ldc methodName invokevirtual java/util/logging/Logger.entering:(Ljava/lang/String;Ljava/lang/String;)V
javac -classpath .:../asm-5.1/lib/\* bytecodeAnnotations/EntryLoggingAgent.java jar cvfm bytecodeAnnotations/EntryLoggingAgent.jar bytecodeAnnotations/EntryLoggingAgent.mf \ bytecodeAnnotations/Entry*.class javac set/SetTest.java java -javaagent:bytecodeAnnotations/EntryLoggingAgent.jar=set.Item -classpath .:../asm-5.1/lib/\* set.SetTest