Skip to content

Lesson 01 · Annotations

Beyond the 1Z0-830 exam

Annotations aren't a named 1Z0-830 objective, but they're everywhere a working developer or SDET looks — JUnit (@Test), Mockito, Spring, Jackson. Understanding retention and how frameworks read annotations at runtime is essential to using and building test tooling.

Objectives

After this lesson you will be able to:

  • Use the built-in annotations and explain what each enforces.
  • Define a custom annotation with @Retention and @Target.
  • Read annotations at runtime with reflection.

Built-in annotations

AnnotationEffect
@Overridecompile error if it doesn't actually override
@FunctionalInterfacecompile error unless exactly one abstract method
@Deprecatedmarks an API as obsolete (warning on use); @Deprecated(since, forRemoval)
@SuppressWarnings("unchecked")silences specific compiler warnings
@SafeVarargssuppresses unsafe-varargs warnings on a safe generic varargs method

Defining a custom annotation

An annotation is declared with @interface. Members look like methods and may have defaults.

java
@Retention(RetentionPolicy.RUNTIME)        // keep it at runtime so reflection can read it
@Target(ElementType.METHOD)                // where it may be placed
@interface Timed {
    String value() default "";             // a member; `value` allows @Timed("x")
    int threshold() default 100;
}

@Timed("login")
void login() { }

@Retention and @Target (meta-annotations)

A meta-annotation annotates an annotation:

  • @Retention — how long it's kept: SOURCE (compiler only, e.g. @Override), CLASS (in the .class but not loaded — the default), or RUNTIME (readable via reflection).
  • @Target — what it can annotate (TYPE, METHOD, FIELD, PARAMETER, …).

Gotcha

Only RUNTIME-retained annotations are visible to reflection. A framework like JUnit can find @Test only because it's RetentionPolicy.RUNTIME — the default CLASS retention would be invisible at runtime.

Reading annotations at runtime

java
Method m = MyTest.class.getMethod("login");
if (m.isAnnotationPresent(Timed.class)) {
    Timed t = m.getAnnotation(Timed.class);
    System.out.println(t.value() + " / " + t.threshold());
}

SDET note

This is exactly how a test runner discovers tests: scan classes, find methods annotated with a RUNTIME annotation, and invoke them reflectively. Writing a tiny annotation + reflective runner is the clearest way to understand JUnit's machinery (Module 14).

Key Takeaways

  • Built-ins: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, @SafeVarargs — each enforces or signals something at compile time.
  • Declare custom annotations with @interface; members have types and optional defaults (value enables the shorthand @A("x")).
  • @Retention(RUNTIME) is required for reflective discovery; @Target restricts placement.
  • Read with isAnnotationPresent/getAnnotation — the basis of test runners and DI frameworks.

Lesson Quiz

Lesson Quiz · Annotations0 / 5
  1. Which retention policy lets reflection read an annotation at runtime?

    • ASOURCE
    • BCLASS
    • CRUNTIME
    • Dall of them
  2. What does @Override do?

    • AGenerates an override
    • BCauses a compile error if the method doesn't actually override one
    • CRuns at runtime
    • DNothing
  3. How do you declare a custom annotation?

    • Aclass @A
    • Binterface A
    • C@interface A
    • Dannotation A
  4. What is the DEFAULT retention if you don't specify @Retention?

    • ASOURCE
    • BCLASS
    • CRUNTIME
    • DThere is no default
  5. Why can JUnit find methods annotated @Test?

    • A@Test is SOURCE-retained
    • B@Test is RUNTIME-retained, so reflection can see it
    • CThe compiler lists them
    • DNaming convention

Next: Reflection (basics). Run the matching code in labs/src/main/java/com/jse21/m11_language/.