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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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

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

Browser testing is essential if you have a website or web applications that users interact with. Manual testing can be very helpful to an extent, but given the multiple browsers available, not to mention versions and operating system, testing everything manually becomes time-consuming and repetitive.

To help automate this process, Selenium is a popular choice for developers, as an open-source tool with a large and active community. What's more, we can further scale our automation testing by running on theLambdaTest cloud-based testing platform.

Read more through our step-by-step tutorial on how to set up Selenium tests with Java and run them on LambdaTest:

>> Automated Browser Testing With Selenium

Partner – Orkes – NPI EA (cat=Java)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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.

1. Overview

When working with inheritance in Java, we often start with an abstract class that defines a common method that all subclasses need to implement. For instance, let’s consider an abstract class Item that defines the method use(). Every subclass of Item (such as Book or Key) may need its own implementation of use(). However, an issue may arise when each subclass requires different arguments for the use() method.

In this tutorial, we’ll explore how to implement an abstract method in Java that accepts a variable number of arguments.

2. Problem Statement

Suppose we have the abstract class Item:

public abstract class Item {
    public abstract void use();
}

In our scenario, the subclass Book needs no arguments, whereas the subclass Key needs both a String (the door identifier) and a Queue (of doors). However, since Java is strongly typed, it doesn’t enable us to easily declare one abstract method and then override it with arbitrary parameters.

Therefore, let’s implement a workaround to handle the issue:

Flowchart of Item<C> with EmptyContext for Book and KeyContext for Key.

In the above flowchart, we see a visual overview of how the classes connect. At the top, the class Item<C> defines the common base. From there, each subclass selects the type of context to work with:

  • The subclass Book works with the context type EmptyContext, which represents the case where no additional data is required
  • The subclass Key works with the context type KeyContext, which contains the door identifier and the queue of doors

Therefore, every subclass has a dedicated context type to model its exact needs.

3. Solution – Typed Context Object Approach

Here, we implement the typed context object approach. The abstract base class contains one method use (C context), in which C is a generic context type. Each subclass selects a C that precisely models the data it needs, keeping the API small and enabling compile-time type safety.

3.1. Item – Abstract Base With Generics

The Item.java file defines the abstract method signature once, using a generic type parameter C for the context:

public abstract class Item<C> {

    public abstract void use(C context);

}

Instead of many use(…) overloads, we now have one use(C) method whereby each subclass decides its own C type.

3.2. EmptyContext – Context for No Arguments

The EmptyContext.java file provides a context for items that require no parameters, such as Book:

package com.example.items;

public final class EmptyContext {
    public static final EmptyContext INSTANCE = new EmptyContext();
    private EmptyContext() {}
}

Book can still implement Item<C>, but with C = EmptyContext, avoiding null and keeping the API consistent.

3.3. KeyContext – Context for Key Parameters

KeyContext contains exactly the data a Key needs (doorId and a Queue of door Strings):

public final class KeyContext {
    private final String doorId;
    private final Queue<String> doorsQueue;

    public KeyContext(String doorId, Queue<String> doorsQueue) {
        this.doorId = doorId;
        this.doorsQueue = doorsQueue;
    }

    public String getDoorId() {
        return doorId;
    }

    public Queue<String> getDoorsQueue() {
        return doorsQueue;
    }
}

Grouping parameters into a named type, in this case, KeyContext, specifies what data is expected and prevents argument-order mistakes. Furthermore, the compiler checks types for us.

3.4. Book – Item That Needs No Data

The Book file represents an item that uses EmptyContext since it requires no parameters:

public class Book extends Item<EmptyContext> {
    private final String title;

    public Book(String title) {
        this.title = title;
    }

    @Override
    public void use(EmptyContext ctx) {
        System.out.println("You read the book: " + title);
    }
}

Although a subclass like Book doesn’t need any arguments, we still need it to fit the same method pattern as other items. That’s why we create EmptyContext, a placeholder object that carries no data. To clarify:

  • Book can implement use(EmptyContext context) without extra arguments
  • Other subclasses, like Key, can use their own context classes with real data

Thus, all items can now share the same uniform method signature.

3.5. Key – Item That Uses KeyContext

Key demonstrates how a class receives a typed context with multiple fields:

package com.example.items;

public class Key extends Item<KeyContext> {
    private final String name;

    public Key(String name) {
        this.name = name;
    }

    @Override
    public void use(KeyContext ctx) {
        System.out.println("Using key '" + name + "' on door: " + ctx.getDoorId());
        System.out.println("Doors remaining in queue: " + ctx.getDoorsQueue().size());
    }
}

So, the Key class can only be used with a KeyContext, and Java’s compiler makes sure of that. Therefore, we don’t need to worry about unsafe type conversions.

4. Tests

At this point, let’s create the test classes BookUnitTest.java and KeyUnitTest.java to verify that Book and Key work correctly.

4.1. BookUnitTest.java

ln this test, let’s verify that calling use() on a Book object works with EmptyContext:

package com.example.items;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

class BookUnitTest {

    @Test
    void givenBook_whenUseWithEmptyContext_thenNoException() {
        Book book = new Book("The Hobbit");

        assertDoesNotThrow(() -> book.use(EmptyContext.INSTANCE));
    }
}

Here’s what the test does:

  • Creates a Book with the title “The Hobbit”
  • Calls its use() method, passing in an EmptyContext
  • The test passes if no exception is thrown

The test confirms that items that don’t require extra data, like Book, can safely use the EmptyContext without runtime errors.

Here, using assertDoesNotThrow verifies that the method executes safely without errors. Our aim is to confirm type-safety and not to test the printed output. Even though we can capture System.out to verify the printed output, keeping the test simple makes it clearer that we’re only validating correct API usage.

Meanwhile, using EmptyContext.INSTANCE also avoids the need to pass null, which can otherwise cause runtime issues. So, even no-argument cases remain consistent with the overall method signature shared across all subclasses.

4.2. KeyUnitTest.java

Next, let’s verify that a Key can safely unlock a door when provided with a KeyContext:

package com.example.items;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import java.util.Queue;
import java.util.LinkedList;

public class KeyUnitTest {

    @Test
    void givenKey_whenUseWithKeyContext_thenNoException() {
        Queue<String> doors = new LinkedList<>();
        doors.add("front-door");
        doors.add("back-door");

        Key key = new Key("MasterKey");
        KeyContext ctx = new KeyContext("front-door", doors);

        assertDoesNotThrow(() -> key.use(ctx));
    }
}

Here’s what the test does:

  • Creates a queue of doors (front-door, back-door)
  • Creates a Key labeled “MasterKey”
  • Constructs a KeyContext with the current door (front-door) and the queue
  • Calls key.use(ctx) and asserts that it doesn’t throw an exception

The test confirms that the Key needs to receive the correct context type (KeyContext), ensuring type safety, and that the method behaves correctly when managing doors. Unlike BookUnitTest, the test here shows a stateful interaction whereby each time a door is unlocked, it’s removed from the queue.

Additionally, it shows how the compiler enforces the correct usage of contexts, since if we tried to pass an EmptyContext to a Key, the code doesn’t even compile. Thus, we can catch accidental misuse early, long before runtime.

4.3. Test Results

Let’s now run our tests:

$ mvn clean test
... 
[INFO] Results:
[INFO] 
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

The output above shows that BookUnitTest.java validates the no-argument case with EmptyContext, whereas KeyUnitTest.java validates the argumented case with KeyContext.

These tests together show the two extremes, where one item requires no data and one item requires multiple pieces of information. Therefore, the typed context object approach is robust, regardless of how many parameters a subclass may need. For instance, adding new items (a Potion class with a PotionContext) would follow the same pattern and only require new tests without altering the abstract base.

Here’s a summary of how our Book and Key items work with their respective contexts:

  • The single abstract method use(C) gives a consistent API for all subclasses
  • Each subclass selects a context type that exactly models the data it needs (zero or many parameters)
  • The compiler enforces types and, as a result, we avoid runtime casts and fragile Object… handling
  • EmptyContext keeps the no-argument case explicit and clean

Thus, the approach is flexible, type-safe, and easy to extend.

5. Conclusion

In this article, we examined how to implement an abstract method in Java that works with a variable set of arguments.

So, we used a typed context object approach, whereby each subclass defines exactly the data it needs through its own context class. In scenarios containing no-argument cases, the EmptyContext ensures the signature method remains uniform without special handling. Additionally, we don’t need unsafe type conversions since the compiler ensures that we always use the correct types.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
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.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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.

Course – LS – NPI (cat=Java)
announcement - icon

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

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments