Keywords: Spring | ObjectMapper | Jackson | JSON Serialization | @JsonProperty
Abstract: This article provides an in-depth exploration of configuring Jackson ObjectMapper in Spring framework to serialize only fields annotated with @JsonProperty. Through analysis of common configuration issues and integration with Spring Boot annotation-based configuration, it offers complete solutions and code examples. The discussion extends to visibility configuration, Spring integration essentials, and best practices for avoiding serialization pitfalls in real-world projects.
Introduction
In modern web application development, JSON serialization is an indispensable technical component. Jackson, as the most popular JSON processing library in the Java ecosystem, has its core component ObjectMapper whose configuration directly impacts serialization behavior. Many developers aim to configure it to serialize only fields with specific annotations, which is particularly important in data-sensitive scenarios.
Problem Analysis
From the user-provided case, it is evident that despite extending ObjectMapper and configuring visibility checkers to limit serialization scope, all fields are still serialized during runtime. This primarily stems from the following reasons:
First, Jackson's visibility configuration needs to work in tandem with annotation strategies. In the provided CompanyObjectMapper configuration, although various visibilities are set to NONE, if annotation detection is not explicitly enabled, the system may still process according to default rules.
Second, Spring version compatibility is also a critical factor. The user employs Spring 3.0.5 and Jackson 1.8.0, where configuration methods differ from newer versions. In older versions, additional configurations might be necessary to ensure custom ObjectMapper is correctly recognized and utilized.
Solution Approach
Based on the best answer guidance, we recommend using Spring Boot's annotation-based configuration, which is more concise and modern. Below is the complete configuration example:
@Configuration
public class JacksonConfiguration {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
// Key configuration: Set visibility strategy
mapper.setVisibility(
mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.NONE)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
);
// Enable annotation detection
mapper.configure(MapperFeature.USE_ANNOTATIONS, true);
return mapper;
}
}In this configuration, we not only replicate the basic setup from the best answer but also add crucial visibility settings and annotation enabling. By setting all visibilities to NONE and enabling annotation detection, the system will serialize only fields explicitly marked with @JsonProperty.
Entity Class Configuration
To align with the above configuration, entity classes must correctly use annotations:
public class NumbersOfNewEvents implements StatusAttribute {
@JsonProperty("newAccepts")
public Integer newAccepts;
@JsonProperty("openRequests")
public Integer openRequests;
// Non-annotated fields will not be serialized
public String internalField;
public NumbersOfNewEvents() {
super();
}
}By adding @JsonProperty annotations to fields requiring serialization, we can precisely control which fields appear in the final JSON output. Non-annotated fields, such as internalField, will not be serialized.
Spring Integration Essentials
When integrating custom ObjectMapper in Spring MVC, note the following points:
For modern Spring Boot applications, the above @Configuration approach automatically registers the ObjectMapper Bean, and Spring will use it for all JSON serialization operations.
For traditional Spring XML configuration, refer to the user's servlet.xml setup, but ensure:
<bean id="jacksonObjectMapper" class="com.yourpackage.JacksonConfiguration" factory-method="objectMapper" />This method creates ObjectMapper instances via factory method, ensuring correct application of configurations.
Advanced Configuration Options
Beyond basic visibility settings, ObjectMapper offers rich configuration options to meet various business needs:
Date Format Configuration: Addressing date serialization issues mentioned in the reference article can be done as follows:
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// Or using Java 8 Time API
mapper.registerModule(new JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);Custom Serializers: For complex serialization requirements, register custom serializers:
SimpleModule module = new SimpleModule();
module.addSerializer(CustomClass.class, new CustomSerializer());
mapper.registerModule(module);Performance Considerations
As noted in the reference article, when using custom ObjectMapper in workflow engines like Camunda, performance impacts must be considered. ObjectMapper creation and configuration are relatively expensive operations; it is advisable to:
1. Use singleton ObjectMapper instances
2. Complete all configurations at application startup
3. Avoid recreating ObjectMapper for each serialization
4. For high-concurrency scenarios, consider thread-safe versions of ObjectMapper or object pooling techniques
Testing Verification
To ensure correct configuration, write comprehensive unit tests:
@SpringBootTest
class ObjectMapperTest {
@Autowired
private ObjectMapper objectMapper;
@Test
void testJsonPropertyOnlySerialization() throws Exception {
NumbersOfNewEvents event = new NumbersOfNewEvents();
event.newAccepts = 10;
event.openRequests = 5;
event.internalField = "secret";
String json = objectMapper.writeValueAsString(event);
// Verify only annotated fields are serialized
assertThat(json).contains("newAccepts");
assertThat(json).contains("openRequests");
assertThat(json).doesNotContain("internalField");
assertThat(json).doesNotContain("secret");
}
}Compatibility Considerations
When dealing with different versions of Jackson and Spring, note API changes:
In Jackson 2.x, visibility configuration methods have evolved:
// Jackson 2.x approach
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE);For users on older Jackson 1.x versions, upgrading to 2.x is recommended for better performance and more features.
Best Practices Summary
Based on this article's analysis and practical experience, we summarize the following best practices:
1. Explicitly Configure Visibility Strategy: Do not rely on defaults; explicitly set all visibility rules
2. Enable Annotation Detection: Ensure USE_ANNOTATIONS feature is enabled
3. Unified Configuration Management: Use consistent ObjectMapper configuration across the application
4. Version Compatibility Checks: Regularly check and use the latest stable Jackson versions
5. Comprehensive Testing: Write thorough test cases for serialization configurations
By adhering to these practices, developers can effectively control JSON serialization behavior, ensuring data security and consistency while maintaining good application performance.