Static Content Filtering

👉 Implementing JSON Response Filtering in Spring Boot REST APIs using @JsonIgnore and @JsonIgnoreProperties


What is Content Filtering?

Content filtering, specifically Static Filtering, refers to the process of removing or omitting certain properties from a Java Response Bean before it is serialized (converted) into the final response format (e.g., JSON or XML) and sent back to the requestor / client. This is a crucial step in securing and optimizing API responses.

💡 In short:
It’s about ensuring only necessary and authorized data leaves your application and reaches to the client.


Table of Contents


Features and use cases

AspectDescription
ScopeApplies to Response Beans (POJOs) used by Spring Controllers for serialization, primarily using the Jackson library.
PurposeTo control the data exposure to the client. This is essential for security and compliance.
Use CaseHiding sensitive fields like passwords, internal IDs, or credit card numbers from non-administrative API consumers.
BenefitsSecurity: Reduces the risk of accidental data leakage. Performance: Smaller response payload size, leading to faster data transfer.
DrawbacksHardcoding: Filters are fixed on the bean itself, making them inflexible across different API endpoints (Static Filtering). Maintenance: Requires updates to the bean class for every property change.

Maven Dependency

The necessary Jackson libraries, including jackson-annotations, are transitively brought in by the Spring-Boot BOM Spring Web Starter. No explicit addition of Jackson annotations is typically needed.

The core functionality for content filtering is provided by the Jackson Annotations library.

  • Artifact ID:jackson-annotations-${version}.jar
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Implementation

The implementation of static filtering is straightforward and only requires changes within the Java Bean (POJO) itself. No modifications are typically needed in the Controller or Service layer.

We use two primary Jackson annotations to enforce static filtering.

AnnotationPurpose
@JsonIgnoreMarks a single property to be ignored during serialization.
@JsonIgnorePropertiesMarks a list of properties (by name) within the class to be ignored.
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/** * Ignore 'property4' and 'property5' for any API response using this bean. 
 */
@JsonIgnoreProperties(value = {"property4", "property5"})
public class SomeBean {

    private String property1;
    
    // Ignore the property property2
    @JsonIgnore
    private String property2;

    private String property3;
    
    // Ignored
    private String property4;
    private String property5;
    
    
    private String property6;

    // constructors, setter-getters and utility methods
}

Project POC:
Refer the POC application for static content filtering: Spring Boot POC App - Static Filtering


Observations

ConceptDescriptionAnnotation/ScopeKey Takeaway
Hardcoded NatureThe filtering logic is applied directly onto the bean definition. Any API endpoint returning this bean will have the same properties filtered out.N/A (Core Mechanism)Leads to inflexible filtering across all uses of the bean.
Static FilteringThe formal name for this approach, as the filtering is determined at compile-time (via annotations) and is constant.N/A (Core Mechanism)This is a bean-level mechanism, not dynamic or per-request.
@JsonIgnoreApplied to a specific field or getter method to completely exclude that property from both JSON output (serialization) and input (deserialization).Property-levelExcludes a single property.
@JsonIgnorePropertiesApplied at the class level to specify a list of property names that should be ignored during serialization.Class-levelExcludes multiple properties by name.
Response EffectWhen a Controller returns an instance of the annotated bean, the Jackson serializer removes the specified properties (property2, property4, property6, etc.) from the final JSON/XML output.N/A (Result)The client receives a JSON/XML payload with a subset of the bean’s fields.

Best Practices

While Static Filtering is simple, we should be aware of its limitations and the superior alternative Dynamic Filtering.

The primary drawback of Static Filtering is its lack of flexibility.

Consider a use-case where two APIs API-A & API-B returns the same bean in response but they have to return different set of properties of the response bean ?

We can’t implement above use-case with Static filtering because the filtering rules are hardcoded in the bean class.

Why use Dynamic filtering ?

In Dynamic Filtering we use @JsonFilter and FilterProvider, which allows us to define filtering rules in runtime.

The controller can dynamically specify which fields to include/exclude for a given request, providing fine-grained control for different use cases or user roles.

This is the preferred approach for complex, multi-role APIs.

  • For use cases where different APIs need different fields from the same bean (e.g., an /admin/users API shows all fields, but a /users/self API only shows public fields)

Separation of Concerns (SoC)

A robust application adheres to SoC. Annotating a Domain Model (the object that represents data in the database) with @JsonIgnore couples the database structure with the API response format.

  • Always use DTOs (Data Transfer Objects) for API responses.
  • KeepsDomain Model clean, focused on business logic and persistence.
  • Use Response DTO solely for the API response.
    • Apply Static Filtering on the DTO properties that are never needed by the client (e.g., version IDs).
    • For fields that sometimes need filtering, use Dynamic Filtering on the DTO.
  • Use Static Filtering for properties that should NEVER be exposed by ANY API endpoint (e.g., the hashed password field in a User entity).

Security Implications

Static filtering is a simple and effective solution, but we must be aware of its limitations. Relying solely on content filtering is not a complete security solution.

Always validate user roles/permissions in the controller/service layer before fetching or returning sensitive data, as filtering is merely a presentation layer safeguard.