Mastering Custom Implementations

Partha Sai Guttikonda
5 min readNov 3, 2024

--

Building a Flexible Singleton Reporting Utility in Java

In the dynamic world of software development, the need for flexible, customizable reporting solutions has grown significantly. In this article, I’ll walk you through a practical approach to creating a customizable reporting class in Java using the Singleton design pattern. This will not only standardize reporting across your project but also allow teams to adapt their own reporting logic with minimal code changes.

Photo by Luke Chesser on Unsplash

Problem Statement:

Reporting is an integral part of software projects, especially those involving extensive testing, such as automated UI testing, API testing, and integration tests. Often, different teams or modules within a project require different reporting structures to cater to their specific needs. For example, a QA team may need detailed logs for Selenium tests, while an API development team might need lightweight, structured API report messages.

The challenge here lies in maintaining a consistent reporting structure while still allowing teams to customize reports to fit their unique requirements. Without a flexible system, developers might end up duplicating code, creating multiple implementations that increase the complexity and maintenance overhead.

Solution: A Singleton-based customizable reporting class that offers a standard interface for reporting and allows developers to plug in their custom implementations without changing the core code.

Photo by Markus Spiske on Unsplash

Designing the Reporting Class

Step 1: Defining the ReportInterface

To ensure a common reporting structure, we start by creating an interface, ReportInterface, which outlines the standard methods that any reporting class should implement. This makes it easy for teams to create their custom implementations that adhere to the same method signatures.

package com.my.project.utils;

public interface ReportInterface {
public void reportSelenium(String status, String message);
public void reportJavaLeanFT(com.hp.lft.sdk.java.Window javaWindow, String status, String message);
public void reportStdWndLeanFT(com.hp.lft.sdk.stdwin.Window stdWindow, String status, String message);
public void reportWpfWndLeanFT(com.hp.lft.sdk.wpf.Window wpfWindow, String status, String message);
public void reportSeeTest(String status, String message);
public void report(String status, String message);
public void logApiReportMessage(String status, String message);
public void reportLink(String linkText, String linkUrl);
public void reportAis(String statusCode, String responseString, String message);
public void createAndMoveSlideshowFile();
public Long getThreadId();
public Boolean getTestCaseInErrorStatus();
}

Step 2: Creating the Singleton Class

The Singleton pattern ensures that only one instance of the reporting utility exists throughout the application’s lifecycle. This instance can be shared across the project, making it efficient and easy to manage.

package com.my.project.utils;

public class SingletonForReporting {
private static ReportInterface reportUtil;

private SingletonForReporting() {}

public static ReportInterface getReportUtil() {
if (reportUtil == null) {
reportUtil = new ReportUtil(); // Default implementation
}
return reportUtil;
}

public static void setReportUtil(ReportInterface userDefined) {
reportUtil = userDefined;
}
}

Step 3: Usage and Customization

Now, developers using the project can create their own custom reporting classes by implementing ReportInterface and set their implementation using SingletonForReporting.setReportUtil(). This ensures their custom logic is used throughout the project without modifying the core code. The following example demonstrates how a custom implementation can be developed in a different project that imports the main project as a JAR dependency.

Example:

package new.project.usage

public class CustomReportUtil implements ReportInterface {
@Override
public void reportSelenium(String status, String message) {
// Custom implementation for Selenium reporting
}

// Implement other methods as needed...
}

// Setting the custom implementation
SingletonForReporting.setReportUtil(new CustomReportUtil());

Important Note:

This customization is done in a separate project by including the original project as a JAR file. This allows external teams or users to create their own reporting logic without altering the main codebase. By integrating the project JAR, developers gain access to the SingletonForReporting class and ReportInterface, ensuring they can extend the functionality while maintaining a clean and modular structure.

To access the reporting utility, users can call:

ReportInterface report = SingletonForReporting.getReportUtil();
report.reportSelenium("Pass", "Test completed successfully.");

Advantages of This Approach

1. Customizability

Teams can implement their specific reporting needs without altering the project’s core code. This flexibility allows each team to define reports in formats that suit their processes, such as generating HTML, PDF, or custom data structures.

2. Reusability

By using the Singleton pattern, the reporting utility remains a single, reusable instance across the entire application, ensuring efficient use of resources and simplifying the management of the reporting class.

3. Standardization

The use of ReportInterface ensures that all custom implementations follow a standardized set of methods. This promotes consistency across different reporting classes, making it easier to maintain and extend the codebase.

4. Ease of Integration

Setting a custom reporting class is as simple as passing an instance to SingletonForReporting.setReportUtil(). This makes the system user-friendly and easy to integrate into existing projects.

Real-World Use Cases

Automated UI Testing

Teams working on Selenium-based UI tests can use reportSelenium() to log detailed reports about their test executions. This method can be customized to include screenshots, timestamps, and other relevant data.

API Reporting

Developers working with APIs can leverage logApiReportMessage() for structured API response logging. This helps standardize how API results are documented across teams.

Slide Creation for Reports

The createAndMoveSlideshowFile() method can be used to automate the generation of slide decks from test reports, which can be useful for presenting test outcomes to stakeholders without manual intervention.

Conclusion

Creating a customizable reporting class using the Singleton design pattern in Java addresses the challenge of maintaining a consistent yet adaptable reporting structure. This approach provides a seamless way for different teams to implement custom reporting without complicating the core project code. By defining a ReportInterface and implementing SingletonForReporting, we empower teams to innovate and adapt their reporting as needed while keeping the overall system standardized and maintainable.

Questions or Comments? Let me know your thoughts below!

Photo by Pete Pedroza on Unsplash

--

--

Partha Sai Guttikonda
Partha Sai Guttikonda

Written by Partha Sai Guttikonda

Engineering Intelligence: ML in Imaging | Full-Stack AI Innovator

No responses yet