Tuesday, September 22, 2026

SAP Commerce Interceptors Explained: Prepare, Validate, Load, Remove & Custom Interceptors

Introduction

Interceptors are one of the most important concepts in SAP Commerce development.

If you have worked with:

  • ModelService
  • Model creation
  • Model save
  • Model update
  • Model removal
  • Validation
  • Business rules
  • Custom itemtypes

you have probably encountered interceptors.

A simple operation such as:

modelService.save(productModel);

can trigger multiple interceptors before and during persistence.

This makes interceptors extremely useful for enforcing business rules and preparing model data.

However, they can also become a source of difficult production issues when developers don't understand when an interceptor executes and what it should be used for.

SAP Commerce provides different interceptor interfaces for different lifecycle stages. For example, ValidateInterceptor runs after preparation and before the model is persisted, while RemoveInterceptor runs before a model is removed.

In this article, we will cover:

  • What interceptors are
  • Interceptor lifecycle
  • InitDefaultsInterceptor
  • PrepareInterceptor
  • ValidateInterceptor
  • LoadInterceptor
  • RemoveInterceptor
  • Custom interceptors
  • Spring configuration
  • Interceptor context
  • isNew()
  • isModified()
  • Avoiding recursive saves
  • Performance considerations
  • Troubleshooting
  • Real production scenarios
  • Senior-level interview questions

1. What Is an Interceptor?

An interceptor is a mechanism that allows SAP Commerce code to execute logic at specific points in a model's lifecycle.

For example:

Create Model
     ↓
Initialize Defaults
     ↓
Prepare
     ↓
Validate
     ↓
Save
     ↓
Load
     ↓
Remove

Instead of putting all business logic directly inside the model or service, an interceptor can execute logic at the appropriate lifecycle stage.


2. Why Do We Need Interceptors?

Suppose you have a custom item:

<itemtype code="CustOrder">
    <attributes>
        <attribute qualifier="orderNumber"
                   type="java.lang.String">
            <modifiers read="true"
                       write="true"
                       optional="false"/>
        </attribute>
    </attributes>
</itemtype>

The business requirement is:

Every CustOrder must have an order number before it is saved.

You could implement this logic in multiple places.

But then you might have:

OCC
  ↓
Service
  ↓
DAO

Backoffice
  ↓
Service

CronJob
  ↓
Service

Impex
  ↓
ModelService

If every path needs the same validation, an interceptor can provide a centralized lifecycle-level check.


3. Main SAP Commerce Interceptor Types

The important interceptor types are:

InitDefaultsInterceptor
PrepareInterceptor
ValidateInterceptor
LoadInterceptor
RemoveInterceptor

Conceptually:

                 Model Lifecycle

                       |
                       v
              InitDefaultsInterceptor
                       |
                       v
                PrepareInterceptor
                       |
                       v
                ValidateInterceptor
                       |
                       v
                     SAVE
                       |
                       v
                LoadInterceptor
                       |
                       v
                    REMOVE
                       |
                       v
                RemoveInterceptor

The exact execution behavior depends on the operation and the configured interceptors.


4. InitDefaultsInterceptor

InitDefaultsInterceptor is used when a model is initialized with default values.

Conceptually:

modelService.create(ProductModel.class);

can result in default initialization logic being applied.

A custom interceptor can provide defaults.

Example:

public class CustomOrderInitDefaultsInterceptor
        implements InitDefaultsInterceptor
{
    @Override
    public void onInitDefaults(
            Object model,
            InterceptorContext ctx)
            throws InterceptorException
    {
        CustOrderModel order = (CustOrderModel) model;

        if (order.getStatus() == null)
        {
            order.setStatus(OrderStatus.NEW);
        }
    }
}

The important concept is:

Create model
     ↓
Initialize default values

SAP Commerce's interceptor APIs document onInitDefaults() as being called by ModelService.initDefaults(Object) after a model is instantiated.


5. PrepareInterceptor

PrepareInterceptor is one of the most frequently used interceptors.

It is intended to prepare model data before persistence.

SAP Commerce calls the interceptor's onPrepare() during ModelService.saveAll().

For example:

public class CustOrderPrepareInterceptor
        implements PrepareInterceptor<CustOrderModel>
{
    @Override
    public void onPrepare(
            CustOrderModel model,
            InterceptorContext ctx)
            throws InterceptorException
    {
        if (model.getOrderNumber() == null)
        {
            model.setOrderNumber(
                UUID.randomUUID().toString()
            );
        }
    }
}

The responsibility here is:

Prepare data

not:

Validate data

6. PrepareInterceptor Example

Suppose your model has:

firstName
lastName
fullName

Business requirement:

fullName = firstName + " " + lastName

A prepare interceptor could do:

public class CustomerPrepareInterceptor
        implements PrepareInterceptor<CustomerModel>
{
    @Override
    public void onPrepare(
            CustomerModel customer,
            InterceptorContext ctx)
            throws InterceptorException
    {
        if (customer.getFirstName() != null &&
            customer.getLastName() != null)
        {
            customer.setFullName(
                customer.getFirstName()
                + " "
                + customer.getLastName()
            );
        }
    }
}

Now:

firstName = John
lastName  = Smith

becomes:

fullName = John Smith

before persistence.


7. Prepare vs Validate

This is one of the most common interview questions.

PrepareInterceptor

Purpose:

Prepare / modify / derive data

Example:

Generate code
Set default value
Calculate derived field
Synchronize related model information

ValidateInterceptor

Purpose:

Validate data

Example:

Mandatory field check
Business validation
Cross-field validation

SAP explicitly describes ValidateInterceptor as being called after required PrepareInterceptors and before saving, and recommends using Prepare for preparation and Validate for validation.


8. ValidateInterceptor

A ValidateInterceptor validates a model before it is saved.

Example:

public class CustOrderValidateInterceptor
        implements ValidateInterceptor<CustOrderModel>
{
    @Override
    public void onValidate(
            CustOrderModel model,
            InterceptorContext ctx)
            throws InterceptorException
    {
        if (model.getOrderNumber() == null)
        {
            throw new InterceptorException(
                "Order number cannot be null"
            );
        }
    }
}

Now:

modelService.save(orderModel);

will fail if:

orderNumber == null

9. Why Throw InterceptorException?

An interceptor can prevent persistence by throwing an exception.

For example:

throw new InterceptorException(
    "Invalid order state"
);

The save operation can then fail.

This is useful when the data violates a mandatory business rule.

Conceptually:

ModelService.save()
       |
       v
Prepare
       |
       v
Validate
       |
       +---- Invalid
       |       |
       |       v
       |    Exception
       |
       +---- Valid
               |
               v
             SAVE

10. LoadInterceptor

A LoadInterceptor is associated with model loading.

Conceptually:

Database
    ↓
ModelService
    ↓
LoadInterceptor
    ↓
Model

It can be used when a model is loaded and additional logic is required.

However, LoadInterceptor should be used carefully.

Loading a model can happen very frequently in a Commerce application.

For example:

ProductModel product =
    modelService.get(pk);

If your LoadInterceptor performs expensive logic, every load can become expensive.


11. Why LoadInterceptor Can Be Dangerous

Imagine:

public void onLoad(
        ProductModel product,
        InterceptorContext ctx)
{
    // expensive FlexibleSearch
}

Now suppose the application loads:

10,000 products

You could accidentally trigger:

10,000 additional queries

This can create a serious performance problem.

Therefore:

Avoid expensive database queries and external service calls inside LoadInterceptors.


12. RemoveInterceptor

RemoveInterceptor executes before a model is removed.

SAP Commerce documentation states that RemoveInterceptor is called before the model is removed from the database. It can be used to prevent removal or remove related models.

Example:

public class CustomOrderRemoveInterceptor
        implements RemoveInterceptor<CustOrderModel>
{
    @Override
    public void onRemove(
            CustOrderModel model,
            InterceptorContext ctx)
            throws InterceptorException
    {
        if (model.isProtectedOrder())
        {
            throw new InterceptorException(
                "Protected order cannot be removed"
            );
        }
    }
}

Now:

modelService.remove(order);

can be prevented.


13. RemoveInterceptor Use Case

Suppose:

Parent
 |
 +---- Child
 |
 +---- Child
 |
 +---- Child

When the parent is removed, business requirements may require related cleanup.

A RemoveInterceptor can participate in that lifecycle.

However, if the relation already has appropriate partof semantics or platform-supported cascading behavior, you should not duplicate that behavior unnecessarily.


14. InterceptorContext

InterceptorContext is extremely important.

The interceptor receives:

InterceptorContext ctx

Example:

@Override
public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
        throws InterceptorException
{
    // logic
}

The context provides information about the current interceptor operation.

It can help answer questions such as:

Is this model new?
Was this attribute modified?
Is this model being removed?

15. Checking Whether a Model Is New

A common pattern is:

if (ctx.isNew(model))
{
    // logic for new model
}

For example:

public void onPrepare(
        CustOrderModel order,
        InterceptorContext ctx)
        throws InterceptorException
{
    if (ctx.isNew(order))
    {
        order.setStatus(OrderStatus.NEW);
    }
}

This avoids applying creation-only logic to every update.


16. Checking Whether an Attribute Changed

A very useful pattern is:

ctx.isModified(model, "status")

For example:

if (ctx.isModified(order, "status"))
{
    // status changed
}

This is extremely useful for performance.

Instead of:

Every save
    ↓
Execute expensive logic

you can use:

Only when relevant attribute changes
    ↓
Execute logic

17. Example: Attribute-Specific Prepare Logic

Suppose an order has:

status
paymentStatus
deliveryStatus

You only want to execute logic when:

paymentStatus

changes.

Use:

@Override
public void onPrepare(
        OrderModel order,
        InterceptorContext ctx)
        throws InterceptorException
{
    if (ctx.isModified(order, "paymentStatus"))
    {
        // Perform payment-related preparation
    }
}

This is much better than executing the logic on every save.


18. Important Rule: Don't Put Everything in Interceptors

This is a common mistake.

Developers sometimes create:

PrepareInterceptor
    ↓
100 lines of business logic
    ↓
FlexibleSearch
    ↓
External REST call
    ↓
Multiple model saves

This makes the persistence lifecycle difficult to understand.

A better architecture is:

Interceptor
    ↓
Small lifecycle-specific logic
    ↓
Service
    ↓
Business logic

For example:

if (ctx.isModified(order, "status"))
{
    orderStatusService.handleStatusChange(order);
}

The interceptor remains small.


19. Interceptor vs Service Layer

This is another important interview topic.

Service Layer

Use for:

Business operations
Workflows
Transactions
Complex business logic
External integrations
Reusable application operations

Interceptor

Use for:

Model lifecycle rules
Preparation
Validation
Load behavior
Remove behavior

For example:

Good:

PrepareInterceptor
    ↓
orderService.prepareOrder(order)

rather than:

PrepareInterceptor
    ↓
50 lines of business logic

20. Custom Interceptor Configuration

A custom interceptor normally needs Spring configuration.

Conceptually:

<bean id="custOrderPrepareInterceptor"
      class="com.example.interceptors.CustOrderPrepareInterceptor"/>

Then register it with the appropriate interceptor configuration for the target type.

The exact Spring/Interceptor configuration differs between SAP Commerce versions and project conventions, so use the corresponding platform configuration supported by your version.

The important architecture is:

Spring Bean
     ↓
Interceptor Registration
     ↓
Target Item Type
     ↓
Lifecycle Event
     ↓
onPrepare/onValidate/etc.

21. Generic vs Typed Interceptors

You may see:

PrepareInterceptor

or:

PrepareInterceptor<ProductModel>

A typed interceptor is preferable when the interceptor is intended for one specific model type.

Example:

public class ProductPrepareInterceptor
        implements PrepareInterceptor<ProductModel>

This gives you stronger compile-time typing.


22. Example: Custom Product ValidateInterceptor

Suppose the requirement is:

A product cannot be approved unless it has a valid code and name.

Implementation:

public class ProductValidateInterceptor
        implements ValidateInterceptor<ProductModel>
{
    @Override
    public void onValidate(
            ProductModel product,
            InterceptorContext ctx)
            throws InterceptorException
    {
        if (product.getCode() == null ||
            product.getCode().trim().isEmpty())
        {
            throw new InterceptorException(
                "Product code is mandatory"
            );
        }

        if (product.getName() == null ||
            product.getName().trim().isEmpty())
        {
            throw new InterceptorException(
                "Product name is mandatory"
            );
        }
    }
}

Now validation is centralized.


23. Example: PrepareInterceptor for Generated Identifier

Suppose:

CustSAPCpiInboundOrder

needs a generated identifier if none is supplied.

You could implement:

public class CustInboundOrderPrepareInterceptor
        implements PrepareInterceptor<CustSAPCpiInboundOrderModel>
{
    @Override
    public void onPrepare(
            CustSAPCpiInboundOrderModel model,
            InterceptorContext ctx)
            throws InterceptorException
    {
        if (ctx.isNew(model) &&
            model.getOrderNumber() == null)
        {
            model.setOrderNumber(
                UUID.randomUUID().toString()
            );
        }
    }
}

This is a good example of using:

PrepareInterceptor
+
InterceptorContext.isNew()

24. Avoid Recursive Save Problems

One of the most important interceptor mistakes is calling:

modelService.save(model);

inside an interceptor unnecessarily.

For example:

public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
{
    product.setName("New Name");

    modelService.save(product);
}

This can cause:

save
 ↓
PrepareInterceptor
 ↓
modelService.save()
 ↓
PrepareInterceptor
 ↓
modelService.save()
 ↓
...

Potentially resulting in recursion, repeated interception, performance problems, or unexpected behavior.

Generally, the interceptor should modify the model and let the original persistence operation continue.

For example:

public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
{
    product.setName("New Name");
}

The original ModelService.save() handles persistence.


25. Interceptor Ordering

Multiple interceptors can exist for the same model type and lifecycle.

For example:

Product
  |
  +---- PrepareInterceptor A
  |
  +---- PrepareInterceptor B
  |
  +---- PrepareInterceptor C

The execution order can matter.

If:

Interceptor A

sets:

attribute X

and:

Interceptor B

depends on X, ordering becomes important.

Do not assume the execution order simply because the beans appear in a particular order in a Spring XML file.

Use the supported interceptor ordering mechanism for your SAP Commerce version.


26. Interceptor Exceptions

An interceptor can throw:

InterceptorException

Example:

throw new InterceptorException(
    "Invalid product state"
);

This can propagate back through the save operation.

At an API layer, the exception may eventually become an OCC error response depending on your exception handling configuration.

Therefore, there can be a chain:

Interceptor
    ↓
InterceptorException
    ↓
Service Layer
    ↓
OCC
    ↓
Error DTO
    ↓
HTTP Response

This connects today's topic directly with the previous OCC error-handling article.


27. Interceptors and Transactions

Interceptors execute as part of model lifecycle operations.

Therefore, you should be careful about performing external operations.

For example:

Save Product
   ↓
Interceptor
   ↓
Call external REST API

If the external API call takes:

5 seconds

your save operation may also be affected.

Worse, if the Commerce transaction later fails, the external system may already have received the request.

This is why external integrations are generally better handled through appropriate service/event/process mechanisms rather than making persistence interceptors perform synchronous external calls.


28. Interceptor Performance

Interceptors execute frequently.

Therefore, performance matters.

Avoid:

FlexibleSearch on every save
External REST call
Large loops
Heavy calculations
Multiple model loads
Repeated saves

Prefer:

Check whether relevant attribute changed
        ↓
Execute only required logic

For example:

if (ctx.isModified(model, "status"))
{
    statusService.process(model);
}

29. A Bad Interceptor Example

@Override
public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
{
    List<ProductModel> products =
        flexibleSearchService.search(
            "SELECT {pk} FROM {Product}"
        ).getResult();

    for (ProductModel p : products)
    {
        // expensive processing
    }
}

Imagine this runs every time a Product is saved.

If the system processes thousands of product saves:

Thousands of saves
       ×
Full product query
       =
Performance problem

This is exactly the type of code that can cause production issues.


30. Better Approach

Instead:

@Override
public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
        throws InterceptorException
{
    if (ctx.isModified(product, "price"))
    {
        productPriceService.handlePriceChange(product);
    }
}

The interceptor is:

  • Small
  • Targeted
  • Easy to test
  • Easier to troubleshoot

31. Interceptor vs Event

Another common interview question:

When should you use an interceptor vs an event?

Use an interceptor when you need to enforce a model lifecycle rule.

Use an event when you want to communicate that something happened and potentially process it asynchronously.

For example:

Product validation
    → ValidateInterceptor

while:

Order placed
    → Event

The event can then trigger additional processing without putting everything into the model save lifecycle.


32. Interceptor vs CronJob

These are also very different.

Interceptor

Triggered by model lifecycle operations.

save()
 ↓
interceptor

CronJob

Triggered according to a schedule or explicit execution.

11:00 PM
 ↓
CronJob

Don't use an interceptor for large batch processing.

Bad:

Product save
 ↓
Process 100,000 products

Better:

CronJob
 ↓
Process batch

33. Real Production Scenario: Save Is Failing

Suppose developers report:

"Product save is failing only in one environment."

The first question should be:

Which interceptor is failing?

Check the stack trace.

Look for:

InterceptorException
PrepareInterceptor
ValidateInterceptor
LoadInterceptor
RemoveInterceptor

Then identify:

Model type
Interceptor class
Attribute
Root exception

For example:

ModelService.save()
    ↓
ValidateInterceptor
    ↓
InterceptorException
    ↓
"Brand is mandatory"

This immediately narrows the problem.


34. Real Production Scenario: Works in DEV but Fails Locally

Suppose:

DEV      → Save works
QA       → Save works
PROD     → Save works
LOCAL    → Save fails

A custom interceptor could be one possible area to investigate.

Check:

1. Extension loaded?
2. Spring bean loaded?
3. Interceptor registration present?
4. Local database data?
5. Local system configuration?
6. Local model state?
7. Local generated classes updated?
8. Local deployment/build complete?

This is especially useful when the exception appears during:

modelService.save(model);

35. Real Production Scenario: Infinite/Repeated Save

Problem:

StackOverflowError

or repeated interceptor execution.

Check whether an interceptor is doing:

modelService.save(model);

inside:

onPrepare()
onValidate()

or triggering another save path indirectly.

A safer pattern is usually:

model.setSomething(value);

and allow the current persistence operation to continue.


36. Real Production Scenario: Validation Error in OCC

Suppose OCC calls:

POST /orders

and the save triggers:

ValidateInterceptor

which throws:

InterceptorException

The flow could be:

OCC Controller
      ↓
Facade
      ↓
Service
      ↓
ModelService.save()
      ↓
ValidateInterceptor
      ↓
Exception
      ↓
OCC Error Handling
      ↓
HTTP Error Response

This is why interceptor errors can appear as API errors even though the actual root cause is in the model lifecycle.


37. Interceptor Debugging Checklist

When debugging an interceptor issue:

1. Identify the model type
2. Identify the lifecycle operation
3. Identify the interceptor type
4. Identify the interceptor class
5. Check interceptor registration
6. Check InterceptorContext conditions
7. Check modified attributes
8. Check custom service calls
9. Check recursive save calls
10. Check FlexibleSearch/external calls
11. Check exception root cause
12. Check environment-specific configuration

38. Interview Question: What Is a PrepareInterceptor?

Answer

A PrepareInterceptor is used to prepare or modify model data before it is persisted.

For example:

@Override
public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
{
    if (ctx.isNew(product))
    {
        product.setCustomFlag(Boolean.TRUE);
    }
}

SAP Commerce invokes onPrepare() during the save lifecycle.


39. Interview Question: What Is a ValidateInterceptor?

Answer

A ValidateInterceptor validates model values before persistence.

Example:

if (product.getCode() == null)
{
    throw new InterceptorException(
        "Product code is mandatory"
    );
}

Validation happens after preparation and before the model is saved.


40. Interview Question: PrepareInterceptor vs ValidateInterceptor?

Answer

PrepareInterceptor
→ Modify / prepare data

ValidateInterceptor
→ Validate data

Example:

Prepare:
Generate order number

Validate:
Order number must not be null

A good rule is:

Prepare the model in PrepareInterceptor; reject invalid data in ValidateInterceptor.


41. Interview Question: When Is RemoveInterceptor Called?

Answer

It is called before a model is removed from the database.

It can be used to:

  • Prevent deletion
  • Perform removal-related validation
  • Clean related data where appropriate

SAP Commerce documents RemoveInterceptor.onRemove() as being called by ModelService.removeAll().


42. Interview Question: Why Should You Avoid Heavy Logic in LoadInterceptor?

Answer

Because model loading can happen very frequently.

If every model load triggers:

FlexibleSearch
REST call
Complex calculation

the application can experience significant performance degradation.

Therefore, LoadInterceptor logic should be lightweight and carefully justified.


43. Interview Question: How Do You Know an Attribute Changed?

Use:

ctx.isModified(model, "attributeQualifier")

Example:

if (ctx.isModified(order, "status"))
{
    // Process status change
}

This avoids unnecessary processing.


44. Interview Question: How Do You Check Whether a Model Is New?

Use:

ctx.isNew(model)

Example:

if (ctx.isNew(product))
{
    // Creation-specific logic
}

This is useful when logic should only run during initial creation.


45. Interview Question: Can You Save a Model Inside a PrepareInterceptor?

Technically, code can invoke ModelService operations, but doing so unnecessarily is dangerous.

A common bad pattern is:

onPrepare()
    ↓
modelService.save(model)
    ↓
onPrepare()
    ↓
modelService.save(model)

This can lead to recursive or repeated interceptor execution.

Prefer:

onPrepare()
    ↓
model.setValue(...)
    ↓
Current save continues

46. Interview Question: Interceptor or Service?

Use an interceptor for lifecycle-specific rules:

"Before this model is persisted, ensure X."

Use a service for business operations:

"Perform the complete order cancellation workflow."

Don't turn interceptors into giant business-service classes.


47. Senior Interview Scenario

Question

You have this code:

public void onPrepare(
        ProductModel product,
        InterceptorContext ctx)
{
    List<ProductModel> products =
        productService.getAllProducts();

    for (ProductModel p : products)
    {
        // processing
    }
}

The application becomes slow when products are imported.

What is wrong?

Answer

The interceptor is executing expensive batch logic during the model persistence lifecycle.

If thousands of products are imported:

Thousands of model saves
        ×
Get all products
        =
Huge processing overhead

The logic should be moved to an appropriate batch/CronJob/process mechanism, or redesigned so that the interceptor performs only the minimum required lifecycle work.


48. Senior Interview Scenario

Question

A custom ValidateInterceptor works in one environment but not another.

What would you check?

Answer

I would verify:

Spring bean
Interceptor registration
Extension loading
Deployment/build
Generated model classes
Database configuration
Environment-specific properties
Data differences
Interceptor enablement/order

Then reproduce the save operation and inspect the full root cause.


49. Senior Interview Scenario

Question

A product save takes 3 seconds after a new interceptor was introduced.

How would you investigate?

Answer

I would profile the interceptor first.

Look for:

FlexibleSearch
ModelService.get()
External API
Loops
Multiple saves
Large collections
Repeated service calls

Then check whether the interceptor executes unnecessarily.

For example:

if (ctx.isModified(product, "price"))
{
    // execute only for price changes
}

This can significantly reduce unnecessary work.


50. Best Practices

Keep interceptors small

Good:

5-30 lines

Bad:

300 lines of business logic

The exact size isn't a rule, but complexity should be minimized.


Use the correct interceptor

Default initialization
→ InitDefaultsInterceptor

Prepare data
→ PrepareInterceptor

Validate data
→ ValidateInterceptor

Load-specific behavior
→ LoadInterceptor

Remove-specific behavior
→ RemoveInterceptor

Check changes

Use:

ctx.isModified(model, "attribute")

when appropriate.


Check new models

Use:

ctx.isNew(model)

when creation-only logic is required.


Avoid recursive saves

Do not unnecessarily call:

modelService.save()

from within an interceptor.


Avoid external calls

Don't make persistence depend on slow external systems unless there is a very strong reason and the transaction/error implications are fully understood.


Don't perform batch processing

Use:

CronJob
Business Process
Event
Service

when the operation is large or asynchronous in nature.


51. Complete Interceptor Lifecycle

For interview revision:

                  MODEL LIFECYCLE

                       |
                       v
             ModelService.create()
                       |
                       v
            InitDefaultsInterceptor
                       |
                       v
                  Model Changes
                       |
                       v
              ModelService.save()
                       |
                       v
              PrepareInterceptor
                       |
                       v
              ValidateInterceptor
                       |
                 +-----+-----+
                 |           |
              Invalid       Valid
                 |           |
                 v           v
             Exception     Database
                             |
                             v
                       ModelService.get()
                             |
                             v
                       LoadInterceptor
                             |
                             v
                       ModelService.remove()
                             |
                             v
                       RemoveInterceptor

The exact interceptor chain can vary according to the operation and configured interceptors, but this is a useful conceptual model.


52. Quick Comparison Table

InterceptorMain PurposeTypical Example
InitDefaultsInterceptorSet initial defaultsDefault status
PrepareInterceptorPrepare/modify modelGenerate identifier
ValidateInterceptorValidate dataMandatory field
LoadInterceptorLogic during model loadLightweight load-related behavior
RemoveInterceptorBefore removalPrevent deletion/cleanup

53. Final Takeaway

Interceptors are a core part of SAP Commerce's service-layer architecture.

The most important distinction is:

Prepare
   ↓
Prepare or modify the model

Validate
   ↓
Check whether the model is valid

And:

InitDefaults
   ↓
Set defaults

Load
   ↓
React to loading

Remove
   ↓
React before deletion

For senior SAP Commerce development, don't just memorize the interfaces.

Understand when they execute, what they should contain, and what should NOT be placed inside them.

A well-designed interceptor should be:

  • Small
  • Fast
  • Lifecycle-specific
  • Easy to test
  • Free from unnecessary database calls
  • Free from unnecessary external calls
  • Careful about recursive saves

The most useful pattern to remember is:

if (ctx.isModified(model, "importantAttribute"))
{
    // Do only the required lifecycle logic
}

and:

if (ctx.isNew(model))
{
    // Creation-specific logic
}

These two patterns are particularly useful in real SAP Commerce projects.

No comments:

Post a Comment