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
- What is Content Filtering?
- Table of Contents
- Features and use cases
- Maven Dependency
- Implementation
- Observations
- Best Practices
Features and use cases
| Aspect | Description |
|---|---|
Scope | Applies to Response Beans (POJOs) used by Spring Controllers for serialization, primarily using the Jackson library. |
Purpose | To control the data exposure to the client. This is essential for security and compliance. |
Use Case | Hiding sensitive fields like passwords, internal IDs, or credit card numbers from non-administrative API consumers. |
Benefits | Security: Reduces the risk of accidental data leakage. Performance: Smaller response payload size, leading to faster data transfer. |
Drawbacks | Hardcoding: 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.
| Annotation | Purpose |
|---|---|
@JsonIgnore | Marks a single property to be ignored during serialization. |
@JsonIgnoreProperties | Marks 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
| Concept | Description | Annotation/Scope | Key Takeaway |
|---|---|---|---|
Hardcoded Nature | The 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 Filtering | The 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. |
@JsonIgnore | Applied to a specific field or getter method to completely exclude that property from both JSON output (serialization) and input (deserialization). | Property-level | Excludes a single property. |
@JsonIgnoreProperties | Applied at the class level to specify a list of property names that should be ignored during serialization. | Class-level | Excludes multiple properties by name. |
Response Effect | When 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/usersAPI shows all fields, but a/users/selfAPI 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
Userentity).
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.