eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

In this article, we’ll talk about a core feature of the Java language – the default annotations available in the JDK.

2. What an Annotation Is

Simply put, annotations are Java types that are preceded by an “@” symbol.

Java has had annotations ever since the 1.5 release. Since then, they’ve shaped the way we’ve designed our applications.

Spring and Hibernate are great examples of frameworks that rely heavily on annotations to enable various design techniques.

Basically, an annotation assigns extra metadata to the source code it’s bound to. By adding an annotation to a method, interface, class, or field, we can:

  1. Inform the compiler about warnings and errors
  2. Manipulate source code at compilation time
  3. Modify or examine behavior at runtime

3. Java Built-in Annotations

Now that we’ve reviewed the basics, let’s take a look at some annotations that ship with core Java. First, there are several that inform compilation:

  1. @Override
  2. @SuppressWarnings
  3. @Deprecated
  4. @SafeVarargs
  5. @FunctionalInterface
  6. @Native

These annotations generate or suppress compiler warnings and errors. Applying them consistently is often a good practice since adding them can prevent future programmer error.

The @Override annotation is used to indicate that a method overrides or replaces the behavior of an inherited method.

@SuppressWarnings indicates we want to ignore certain warnings from a part of the code. The @SafeVarargs annotation also acts on a type of warning related to using varargs.

The @Deprecated annotation can be used to mark an API as not intended for use anymore. Moreover, this annotation has been retrofitted in Java 9 to represent more information about the deprecation.

For all these, you can find more detailed information in the articles linked.

3.1. @FunctionalInterface

Java 8 allows us to write code in a more functional way.

Single Abstract Method interfaces are a big part of this. If we intend a SAM interface to be used by lambdas, we can optionally mark it as such with @FunctionalInterface:

@FunctionalInterface
public interface Adder {
    int add(int a, int b);
}

Like @Override with methods, @FunctionalInterface declares our intentions with Adder.

Now, whether we use @FunctionalInterface or not, we can still use Adder in the same way:

Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);

But if we add a second method to Adder, then the compiler will complain:

@FunctionalInterface
public interface Adder { 
    // compiler complains that the interface is not a SAM
    
    int add(int a, int b);
    int div(int a, int b);
}

Now, this would’ve compiled without the @FunctionalInterface annotation. So, what does it give us?

Like @Override, this annotation protects us against future programmer errors. Even though it’s legal to have more than one method on an interface, it isn’t when that interface is being used as a lambda target. Without this annotation, the compiler would break in the dozens of places where Adder was used as a lambda. Now, it just breaks in Adder itself.

3.2. @Native

As of Java 8, there is a new annotation in the java.lang.annotation package called NativeThe @Native annotation is only applicable to fields. It indicates the annotated field is a constant that may be referenced from the native code. For instance, here’s how it’s used in the Integer class:

public final class Integer {
    @Native public static final int MIN_VALUE = 0x80000000;
    // omitted
}

This annotation can also serve as a hint for the tools to generate some auxiliary header files.

4. Meta-Annotations

Next, meta-annotations are annotations that can be applied to other annotations.

For example, these meta-annotations are used for annotation configuration:

  1. @Target
  2. @Retention
  3. @Inherited
  4. @Documented
  5. @Repeatable

4.1. @Target

The scope of annotations can vary based on the requirements. While one annotation is only used with methods, another annotation can be consumed with constructor and field declarations.

To determine the target elements of a custom annotation, we need to label it with a @Target annotation.

@Target can work with 12 different element types. If we look at the source code of @SafeVarargs, then we can see that it must be only attached to constructors or methods:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {
}

4.2. @Retention

Some annotations are meant to be used as hints for the compiler, while others are used at runtime.

We use the @Retention annotation to say where in our program’s lifecycle our annotation applies.

To do this, we need to configure @Retention with one of three retention policies:

  1. RetentionPolicy.SOURCE – visible by neither the compiler nor the runtime
  2. RetentionPolicy.CLASS – visible by the compiler
  3. RetentionPolicy.RUNTIME – visible by the compiler and the runtime

If no @Retention annotation is present on the annotation declaration, then the retention policy defaults to RetentionPolicy.CLASS.

If we have an annotation that should be accessible at runtime:

@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface RetentionAnnotation {
}

Then, if we add some annotations to a class:

@RetentionAnnotation
@Generated("Available only on source code")
public class AnnotatedClass {
}

Now we can reflect on AnnotatedClass to see how many annotations are retained:

@Test
public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
    AnnotatedClass anAnnotatedClass = new AnnotatedClass();
    Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
    assertThat(annotations.length, is(1));
}

The value is 1 because @RetentionAnnotation has a retention policy of RUNTIME, while @Generated doesn’t.

4.3. @Inherited

In some situations, we may need a subclass to have the annotations bound to a parent class.

We can use the @Inherited annotation to make our annotation propagate from an annotated class to its subclasses.

If we apply @Inherited to our custom annotation and then apply it to BaseClass:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {
}

@InheritedAnnotation
public class BaseClass {
}

public class DerivedClass extends BaseClass {
}

Then, after extending the BaseClass, we should see that DerivedClass appears to have the same annotation at runtime:

@Test
public void whenAnnotationInherited_thenShouldExist() {
    DerivedClass derivedClass = new DerivedClass();
    InheritedAnnotation annotation = derivedClass.getClass()
      .getAnnotation(InheritedAnnotation.class);
 
    assertThat(annotation, instanceOf(InheritedAnnotation.class));
}

Without the @Inherited annotation, the above test would fail.

4.4. @Documented

By default, Java doesn’t document the usage of annotations in Javadocs.

But we can use the @Documented annotation to change Java’s default behavior.

If we create a custom annotation that uses @Documented:

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCell {
    int value();
}

And, apply it to the appropriate Java element:

public class Employee {
    @ExcelCell(0)
    public String name;
}

Then, the Employee Javadoc will reveal the annotation usage:

Field Detail

4.5. @Repeatable

Sometimes it can be useful to specify the same annotation more than once on a given Java element.

Before Java 7, we had to group annotations together into a single container annotation:

@Schedules({
    @Schedule(time = "15:05"),
    @Schedule(time = "23:00")
})
void scheduledAlarm() {
}

However, Java 7 brought a cleaner approach. With the @Repeatable annotation, we can make an annotation repeatable:

@Repeatable(Schedules.class)
public @interface Schedule {
    String time() default "09:00";
}

To use @Repeatable, we need to have a container annotation, too. In this case, we’ll reuse @Schedules:

public @interface Schedules {
    Schedule[] value();
}

Of course, this looks a lot like what we had before Java 7. But, the value now is that the wrapper @Schedules isn’t specified anymore when we need to repeat @Schedule:

@Schedule
@Schedule(time = "15:05")
@Schedule(time = "23:00")
void scheduledAlarm() {
}

Because Java requires the wrapper annotation, it was easy for us to migrate from pre-Java 7 annotation lists to repeatable annotations.

5. Conclusion

In this article, we’ve talked about Java built-in annotations that every Java developer should be familiar with.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)