How to implement marker interfaces in Apex?

Introduction

In this article, I want to discuss a topic that’s well-known in the Java world but hasn’t received much attention in Salesforce Apex: marker interfaces.
At the time of writing this, I wasn’t able to find any blog posts or documentation covering this topic, so I thought it would be a good idea to explain what they are and how they can be useful for Apex developers.

First things first – what exactly the marker interfaces?
According to Wikipedia, “the marker interface pattern is a design pattern in computer science, used with languages that provide run-time type information about objects. It provides a means to associate metadata with a class where the language does not have explicit support for such metadata.”
That’s quite a mouthful. Thankfully, the next sentence clarifies things: “to use this pattern, a class implements a marker interface (also called a tagging interface), which is an empty interface.”
So, after all that jargon, a marker interface is simply an empty interface.
But how can an empty interface be useful? To understand that, let’s see how Salesforce itself uses them.

Examples of Salesforce’s Native Marker Interfaces

Marker interfaces are heavily used in Aura components.
If you’ve worked with the Aura framework, you’ve probably used them hundreds of times:

<aura:component implements="force:lightningQuickAction,force:hasRecordId">

Each marker interface modifies the component’s behavior or adds new functionality. You can find the full list of Aura interfaces here . There are also a few examples in Apex: Database.AllowsCallouts` and `Database.Stateful
All of these interfaces share one important characteristic: they don’t require you to implement any methods, yet they still influence how your class behaves.

Implement Your Own Marker Interface in Apex

Let’s start with a simple example. First, create a marker interface:

public interface MyMarkerInterface {}

Next, create a concrete class that implements it:

public class MyConcreteClass implements MyMarkerInterface{}

Now, let’s verify that the class implements this interface:

List<ApexTypeImplementor> implementor = [
    SELECT Id
    FROM ApexTypeImplementor 
    WHERE ClassName = 'MyConcreteClass'
    AND InterfaceName = 'MyMarkerInterface'
    AND IsConcrete = true
];
Assert.areEqual(1, implementor.size(), 'We are able to check if MyConcreteClass implements MyMarkerInterface');

No System.AssertException is thrown, so we did a first small step, marker interface is implemented. However, let’s not celebrate just yet. In its current form, it’s completely useless.

What Can We Use Marker Interfaces For?

So far, we just have a class implementing an empty interface.
We know how to check for it, but how do we actually make use of it?
Let’s imagine we’re working as an ISV provider. Our product is an advanced LWC component that delivers a great shopping cart and payment experience. The only thing left is the payment method, which should be provided by the subscribing org. So we expose the following interface:

public interface IPaymentMethod {
    String pay(Decimal amount, Map<String, Object> parameters);
}

Subscribers then implement their own payment methods:

public class PayPalPayment implements IPaymentMethod {
    public String pay(Decimal amount, Map<String,Object> parameters){
        System.debug('Paypal payment method implementation');
        return 'SUCCESS';
    }
}

In the managed package, we have a PaymentProcessor class that uses the IPaymentMethod interface:

public class PaymentProcessor {

    public String processPayment(Decimal amount) {
        IPaymentMethod paymentMethod = new PaymentFactory().getPaymentMethod();
        String paymentStatus = paymentMethod.pay(amount, new Map<String, Object>());
        return paymentStatus; 
    }
    public class PaymentFactory {
        public IPaymentMethod getPaymentMethod() {
            return new PayPalPayment();
        }
    }
}

Your payment gateway becomes a huge success, hundreds organizations use it (and pay for it). But you want to make it even better. You come up with an idea to provide built-in payment confirmations. You want to make it easy for developers to add one or more predefined confirmation methods, with minimal code changes.
Let’s use marker interfaces for this.
We’ll define two new confirmation modes – SMS and Email as separate marker interfaces:

public interface SmsPaymentConfirmation {}

public interface EmailPaymentConfirmation {}

Developers can decide whether to add one or both to their payment method simply by modifying their class declaration:

public class PayPalPayment implements IPaymentMethod, SmsPaymentConfirmation, EmailPaymentConfirmation {

    public String pay(Decimal amount, Map<String,Object> parameters){
        System.debug('Paypal payment method implementation');
        return 'SUCCESS';
    }
}

In this example, the developer chose to apply both confirmation methods to the PayPal implementation. Now, let’s see how easy it is to use these marker interfaces in code. We’ll check whether the payment method implements a given interface using the instanceof keyword:

public class PaymentProcessor {

    public String processPayment(Decimal amount) {
        IPaymentMethod paymentMethod = new PaymentFactory().getPaymentMethod();
        String paymentStatus = paymentMethod.pay(amount, new Map<String, Object>());

        //handle SMS confirmation
        if(paymentMethod instanceof SmsPaymentConfirmation) {
            System.debug('Implementation of Sms payment confirmation');
        }

        //handle Email confirmation
        if(paymentMethod instanceOf EmailPaymentConfirmation) {
            System.debug('Implementation of Email payment confirmation'); 
        }

        return paymentStatus; 

    }

    public class PaymentFactory {
        public IPaymentMethod getPaymentMethod() {
            return new PayPalPayment();
        }
    }
}

Thanks to the marker interface pattern, we’ve added predefined behavior to the existing implementations without modifying their code. Now it can be tested:

    new PaymentProcessor().processPayment(100);

In the debug logs you will see that the conditional logic was executed:

14:39:25.3 (32400211)|USER_DEBUG|[4]|DEBUG|Paypal payment method implementation
14:39:25.3 (32535517)|USER_DEBUG|[9]|DEBUG|Implementation of Sms payment confirmation
14:39:25.3 (32583238)|USER_DEBUG|[14]|DEBUG|Implementation of Email payment confirmation

Summary

Marker interfaces offer a simple yet flexible way to modify the behavior of your class implementations. Since Apex allows implementing multiple interfaces in one class, marker interfaces can often be more practical than abstract classes, aligning well with the principle of composition over inheritance.
In my next post, I’ll show how I use this approach in a small framework that makes it easy to log uncaught errors in batch classes using just one line of code. Stay tuned. 🙂


If you have any questions feel free to ask in the comment section below. 🙂

Was it helpful? Check out our other posts here.

Adam Osiecki
Adam Osiecki
Salesforce Developer
Salesforce developer, passionate about delivering well-crafted solutions, always willing to walk an extra mile to get the job done. Working with Salesforce platform since 2017.