Composite Pattern in a Spring Boot Project

📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.

▶️ Subscribe to My YouTube Channel (176K+ subscribers): Java Guides on YouTube

▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube

In real-world backend development, especially in Spring Boot applications, you’ll often work with tree-like structures — such as product categories, menu items, permissions, organizational hierarchies, etc.

If you’ve ever struggled to manage a structure where both individual elements and groups of elements should be treated the same way, then the Composite Pattern can help.

In this article, we’ll cover:

  • What the Composite Pattern is (in plain words)
  • Where it's used in backend systems
  • A full real-world example in Spring Boot — building a product category tree
  • Step-by-step code with explanations
  • Best practices and when not to use it

Let’s dive in.


🧠 What is the Composite Pattern?

The Composite Pattern is a structural design pattern used to treat individual objects and groups of objects in the same way.

You build a structure where both “leaf” and “composite” objects implement the same interface.

In simpler terms:

  • A category may have subcategories
  • A menu item may have submenus
  • A task may have subtasks

And you want to perform the same operation (like display, count, search) no matter whether it’s a single item or a group.


📦 Real-World Example: Product Category Tree in E-Commerce

Let’s say you’re building an e-commerce app. You have product categories like this:

Electronics
├── Phones
│   ├── Android
│   └── iPhone
├── Laptops
├── Accessories

Each category might:

  • Have a name
  • Have child categories
  • Perform an operation (e.g., print itself, collect product IDs, etc.)

Let’s implement this using the Composite Pattern in Spring Boot.


✅ Step 1: Create the Common Interface

public interface CategoryComponent {
    String getName();
    void print();
}

This will be used for both single categories and categories with children.


✅ Step 2: Create the Leaf — Simple Category

public class CategoryLeaf implements CategoryComponent {

    private final String name;

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

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void print() {
        System.out.println("- " + name);
    }
}

This is a leaf node — it doesn’t have children.


✅ Step 3: Create the Composite — Category with Subcategories

import java.util.ArrayList;
import java.util.List;

public class CategoryComposite implements CategoryComponent {

    private final String name;
    private final List<CategoryComponent> children = new ArrayList<>();

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

    public void add(CategoryComponent component) {
        children.add(component);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void print() {
        System.out.println("+ " + name);
        for (CategoryComponent child : children) {
            child.print();
        }
    }
}

This class contains other components — which could be leaves or other composites.


✅ Step 4: Create a Service to Build and Use the Tree

import org.springframework.stereotype.Service;

@Service
public class CategoryService {

    public CategoryComponent buildCategoryTree() {
        CategoryComposite electronics = new CategoryComposite("Electronics");

        CategoryComposite phones = new CategoryComposite("Phones");
        phones.add(new CategoryLeaf("Android"));
        phones.add(new CategoryLeaf("iPhone"));

        CategoryComposite laptops = new CategoryComposite("Laptops");
        laptops.add(new CategoryLeaf("Gaming"));
        laptops.add(new CategoryLeaf("Business"));

        CategoryLeaf accessories = new CategoryLeaf("Accessories");

        electronics.add(phones);
        electronics.add(laptops);
        electronics.add(accessories);

        return electronics;
    }

    public void displayCategories(CategoryComponent root) {
        root.print();
    }
}

Here we build the full category tree and print it using the same method (print()) on any component — leaf or composite.


✅ Step 5: Create a REST Controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/categories")
public class CategoryController {

    @Autowired
    private CategoryService categoryService;

    @GetMapping("/print")
    public String printTree() {
        CategoryComponent root = categoryService.buildCategoryTree();
        categoryService.displayCategories(root);
        return "Category tree printed to console.";
    }
}

When you call /api/categories/print, it prints:

+ Electronics
+ Phones
- Android
- iPhone
+ Laptops
- Gaming
- Business
- Accessories

Why This Pattern Fits Here

Need How Composite Pattern Helps
Multiple nested levels Handles tree structures cleanly
Unified operations Call print() on any component
Flexible structure Add more subcategories without rewriting logic
Reusability Use the same interface across services or APIs

Extend with More Features

You can add more methods to CategoryComponent, like:

List<String> getAllCategoryNames();

And implement it differently in CategoryLeaf and CategoryComposite.

This allows recursive operations across your category tree — searching, exporting, counting, etc.


Where Else Can You Use This Pattern?

Use Case Example
Permissions User → Roles → Permissions
Menus Menu → Submenu → Action
Tasks Task → Subtasks → Sub-subtasks
File Systems Directory → Files/Subdirectories
Organization Charts Department → Teams → Members

✅ Best Practices

  1. Keep the interface small – only methods common to all components
  2. Use recursion with care – especially for very deep trees
  3. Avoid direct instanceof checks – rely on polymorphism
  4. Use Spring services only when needed – keep composites simple and stateless if possible
  5. Build trees outside of the controller – separate concerns cleanly

⚠️ When Not to Use Composite Pattern

Avoid this pattern if:

  • You don’t have nested or hierarchical data
  • The structure is always flat
  • You only deal with one type of object

In those cases, a simple list or map might be enough.


Summary

Step What We Did
1 Created a CategoryComponent interface
2 Implemented CategoryLeaf for basic categories
3 Implemented CategoryComposite for nested categories
4 Built a category tree in a Spring Boot service
5 Printed the tree via a controller endpoint

The Composite Pattern lets you treat complex trees the same way you treat single nodes — keeping your logic simple and scalable.


Final Thoughts

Tree-like data structures are everywhere in backend applications. The Composite Pattern gives you a clean, reusable way to model them — especially in Java and Spring Boot projects.

By applying this pattern:

  • You simplify your logic
  • Avoid repetitive code
  • Make it easy to extend the structure in the future

If you find yourself writing recursive logic with a mix of “item” and “group of items” — it's probably time to use the Composite Pattern.

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare